/* * CREATE CONVERSION */ void CreateConversionCommand(CreateConversionStmt *stmt) { Oid namespaceId; char *conversion_name; AclResult aclresult; int from_encoding; int to_encoding; Oid funcoid; const char *from_encoding_name = stmt->for_encoding_name; const char *to_encoding_name = stmt->to_encoding_name; List *func_name = stmt->func_name; static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID}; /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, &conversion_name); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); /* Check the encoding names */ from_encoding = pg_char_to_encoding(from_encoding_name); if (from_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source encoding \"%s\" does not exist", from_encoding_name))); to_encoding = pg_char_to_encoding(to_encoding_name); if (to_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("destination encoding \"%s\" does not exist", to_encoding_name))); /* * Check the existence of the conversion function. Function name could * be a qualified name. */ funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs, false); /* Check we have EXECUTE rights for the function */ aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(func_name)); /* * All seem ok, go ahead (possible failure would be a duplicate * conversion name) */ ConversionCreate(conversion_name, namespaceId, GetUserId(), from_encoding, to_encoding, funcoid, stmt->def); }
/* * DefineAggregate * * "oldstyle" signals the old (pre-8.2) style where the aggregate input type * is specified by a BASETYPE element in the parameters. Otherwise, * "args" defines the input type(s). */ Oid DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) { char *aggName; Oid aggNamespace; AclResult aclresult; List *transfuncName = NIL; List *finalfuncName = NIL; List *sortoperatorName = NIL; TypeName *baseType = NULL; TypeName *transType = NULL; char *initval = NULL; Oid *aggArgTypes; int numArgs; Oid transTypeId; char transTypeType; ListCell *pl; /* Convert list of names to a name and namespace */ aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(aggNamespace)); foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); /* * sfunc1, stype1, and initcond1 are accepted as obsolete spellings * for sfunc, stype, initcond. */ if (pg_strcasecmp(defel->defname, "sfunc") == 0) transfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "sfunc1") == 0) transfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "finalfunc") == 0) finalfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "sortop") == 0) sortoperatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "basetype") == 0) baseType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "stype") == 0) transType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "stype1") == 0) transType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "initcond") == 0) initval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "initcond1") == 0) initval = defGetString(defel); else ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("aggregate attribute \"%s\" not recognized", defel->defname))); }
/* * CREATE COLLATION */ ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists) { char *collName; Oid collNamespace; AclResult aclresult; ListCell *pl; DefElem *fromEl = NULL; DefElem *localeEl = NULL; DefElem *lccollateEl = NULL; DefElem *lcctypeEl = NULL; DefElem *providerEl = NULL; DefElem *versionEl = NULL; char *collcollate = NULL; char *collctype = NULL; char *collproviderstr = NULL; int collencoding; char collprovider = 0; char *collversion = NULL; Oid newoid; ObjectAddress address; collNamespace = QualifiedNameGetCreationNamespace(names, &collName); aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(collNamespace)); foreach(pl, parameters) { DefElem *defel = lfirst_node(DefElem, pl); DefElem **defelp; if (pg_strcasecmp(defel->defname, "from") == 0) defelp = &fromEl; else if (pg_strcasecmp(defel->defname, "locale") == 0) defelp = &localeEl; else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) defelp = &lccollateEl; else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) defelp = &lcctypeEl; else if (pg_strcasecmp(defel->defname, "provider") == 0) defelp = &providerEl; else if (pg_strcasecmp(defel->defname, "version") == 0) defelp = &versionEl; else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("collation attribute \"%s\" not recognized", defel->defname), parser_errposition(pstate, defel->location))); break; } *defelp = defel; }
/* * Try to lookup another operator (commutator, etc) * * If not found, check to see if it is exactly the operator we are trying * to define; if so, return InvalidOid. (Note that this case is only * sensible for a commutator, so we error out otherwise.) If it is not * the same operator, create a shell operator. */ static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, bool isCommutator) { Oid other_oid; bool otherDefined; char *otherName; Oid otherNamespace; AclResult aclresult; other_oid = OperatorLookup(otherOp, otherLeftTypeId, otherRightTypeId, &otherDefined); if (OidIsValid(other_oid)) { /* other op already in catalogs */ return other_oid; } otherNamespace = QualifiedNameGetCreationNamespace(otherOp, &otherName); if (strcmp(otherName, operatorName) == 0 && otherNamespace == operatorNamespace && otherLeftTypeId == leftTypeId && otherRightTypeId == rightTypeId) { /* * self-linkage to this operator; caller will fix later. Note that * only self-linkage for commutation makes sense. */ if (!isCommutator) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("operator cannot be its own negator or sort operator"))); return InvalidOid; } /* not in catalogs, different from operator, so make shell */ aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(otherNamespace)); other_oid = OperatorShellMake(otherName, otherNamespace, otherLeftTypeId, otherRightTypeId); return other_oid; }
/* * CREATE COLLATION */ Oid DefineCollation(List *names, List *parameters) { char *collName; Oid collNamespace; AclResult aclresult; ListCell *pl; DefElem *fromEl = NULL; DefElem *localeEl = NULL; DefElem *lccollateEl = NULL; DefElem *lcctypeEl = NULL; char *collcollate = NULL; char *collctype = NULL; Oid newoid; collNamespace = QualifiedNameGetCreationNamespace(names, &collName); aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(collNamespace)); foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); DefElem **defelp; if (pg_strcasecmp(defel->defname, "from") == 0) defelp = &fromEl; else if (pg_strcasecmp(defel->defname, "locale") == 0) defelp = &localeEl; else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) defelp = &lccollateEl; else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) defelp = &lcctypeEl; else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("collation attribute \"%s\" not recognized", defel->defname))); break; } *defelp = defel; }
/* * DefineAggregate * * "oldstyle" signals the old (pre-8.2) style where the aggregate input type * is specified by a BASETYPE element in the parameters. Otherwise, * "args" is a pair, whose first element is a list of FunctionParameter structs * defining the agg's arguments (both direct and aggregated), and whose second * element is an Integer node with the number of direct args, or -1 if this * isn't an ordered-set aggregate. * "parameters" is a list of DefElem representing the agg's definition clauses. */ ObjectAddress DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, const char *queryString) { char *aggName; Oid aggNamespace; AclResult aclresult; char aggKind = AGGKIND_NORMAL; List *transfuncName = NIL; List *finalfuncName = NIL; List *combinefuncName = NIL; List *serialfuncName = NIL; List *deserialfuncName = NIL; List *mtransfuncName = NIL; List *minvtransfuncName = NIL; List *mfinalfuncName = NIL; bool finalfuncExtraArgs = false; bool mfinalfuncExtraArgs = false; List *sortoperatorName = NIL; TypeName *baseType = NULL; TypeName *transType = NULL; TypeName *serialType = NULL; TypeName *mtransType = NULL; int32 transSpace = 0; int32 mtransSpace = 0; char *initval = NULL; char *minitval = NULL; char *parallel = NULL; int numArgs; int numDirectArgs = 0; oidvector *parameterTypes; ArrayType *allParameterTypes; ArrayType *parameterModes; ArrayType *parameterNames; List *parameterDefaults; Oid variadicArgType; Oid transTypeId; Oid serialTypeId = InvalidOid; Oid mtransTypeId = InvalidOid; char transTypeType; char mtransTypeType = 0; char proparallel = PROPARALLEL_UNSAFE; ListCell *pl; /* Convert list of names to a name and namespace */ aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(aggNamespace)); /* Deconstruct the output of the aggr_args grammar production */ if (!oldstyle) { Assert(list_length(args) == 2); numDirectArgs = intVal(lsecond(args)); if (numDirectArgs >= 0) aggKind = AGGKIND_ORDERED_SET; else numDirectArgs = 0; args = (List *) linitial(args); } /* Examine aggregate's definition clauses */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); /* * sfunc1, stype1, and initcond1 are accepted as obsolete spellings * for sfunc, stype, initcond. */ if (pg_strcasecmp(defel->defname, "sfunc") == 0) transfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "sfunc1") == 0) transfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "finalfunc") == 0) finalfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "combinefunc") == 0) combinefuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "serialfunc") == 0) serialfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0) deserialfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "msfunc") == 0) mtransfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "minvfunc") == 0) minvtransfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0) mfinalfuncName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0) finalfuncExtraArgs = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0) mfinalfuncExtraArgs = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "sortop") == 0) sortoperatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "basetype") == 0) baseType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "hypothetical") == 0) { if (defGetBoolean(defel)) { if (aggKind == AGGKIND_NORMAL) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("only ordered-set aggregates can be hypothetical"))); aggKind = AGGKIND_HYPOTHETICAL; } } else if (pg_strcasecmp(defel->defname, "stype") == 0) transType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "serialtype") == 0) serialType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "stype1") == 0) transType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "sspace") == 0) transSpace = defGetInt32(defel); else if (pg_strcasecmp(defel->defname, "mstype") == 0) mtransType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "msspace") == 0) mtransSpace = defGetInt32(defel); else if (pg_strcasecmp(defel->defname, "initcond") == 0) initval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "initcond1") == 0) initval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "minitcond") == 0) minitval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "parallel") == 0) parallel = defGetString(defel); else ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("aggregate attribute \"%s\" not recognized", defel->defname))); }
/* * CREATE CONVERSION */ ObjectAddress CreateConversionCommand(CreateConversionStmt *stmt) { Oid namespaceId; char *conversion_name; AclResult aclresult; int from_encoding; int to_encoding; Oid funcoid; const char *from_encoding_name = stmt->for_encoding_name; const char *to_encoding_name = stmt->to_encoding_name; List *func_name = stmt->func_name; static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID}; char result[1]; /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, &conversion_name); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); /* Check the encoding names */ from_encoding = pg_char_to_encoding(from_encoding_name); if (from_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source encoding \"%s\" does not exist", from_encoding_name))); to_encoding = pg_char_to_encoding(to_encoding_name); if (to_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("destination encoding \"%s\" does not exist", to_encoding_name))); /* * Check the existence of the conversion function. Function name could be * a qualified name. */ funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs, false); /* Check it returns VOID, else it's probably the wrong function */ if (get_func_rettype(funcoid) != VOIDOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("encoding conversion function %s must return type %s", NameListToString(func_name), "void"))); /* Check we have EXECUTE rights for the function */ aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(func_name)); /* * Check that the conversion function is suitable for the requested source * and target encodings. We do that by calling the function with an empty * string; the conversion function should throw an error if it can't * perform the requested conversion. */ OidFunctionCall5(funcoid, Int32GetDatum(from_encoding), Int32GetDatum(to_encoding), CStringGetDatum(""), CStringGetDatum(result), Int32GetDatum(0)); /* * All seem ok, go ahead (possible failure would be a duplicate conversion * name) */ return ConversionCreate(conversion_name, namespaceId, GetUserId(), from_encoding, to_encoding, funcoid, stmt->def); }
/* * DefineOperator * this function extracts all the information from the * parameter list generated by the parser and then has * OperatorCreate() do all the actual work. * * 'parameters' is a list of DefElem */ ObjectAddress DefineOperator(List *names, List *parameters) { char *oprName; Oid oprNamespace; AclResult aclresult; bool canMerge = false; /* operator merges */ bool canHash = false; /* operator hashes */ List *functionName = NIL; /* function for operator */ TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName2 = NULL; /* second type name */ Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId2 = InvalidOid; Oid rettype; List *commutatorName = NIL; /* optional commutator operator name */ List *negatorName = NIL; /* optional negator operator name */ List *restrictionName = NIL; /* optional restrict. sel. procedure */ List *joinName = NIL; /* optional join sel. procedure */ Oid functionOid; /* functions converted to OID */ Oid restrictionOid; Oid joinOid; Oid typeId[2]; /* to hold left and right arg */ int nargs; ListCell *pl; /* Convert list of names to a name and namespace */ oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(oprNamespace)); /* * loop over the definition list and extract the information we need. */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); if (pg_strcasecmp(defel->defname, "leftarg") == 0) { typeName1 = defGetTypeName(defel); if (typeName1->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SETOF type not allowed for operator argument"))); } else if (pg_strcasecmp(defel->defname, "rightarg") == 0) { typeName2 = defGetTypeName(defel); if (typeName2->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SETOF type not allowed for operator argument"))); } else if (pg_strcasecmp(defel->defname, "procedure") == 0) functionName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "commutator") == 0) commutatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "negator") == 0) negatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "restrict") == 0) restrictionName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "join") == 0) joinName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "hashes") == 0) canHash = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "merges") == 0) canMerge = defGetBoolean(defel); /* These obsolete options are taken as meaning canMerge */ else if (pg_strcasecmp(defel->defname, "sort1") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "sort2") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "ltcmp") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "gtcmp") == 0) canMerge = true; else { /* WARNING, not ERROR, for historical backwards-compatibility */ ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("operator attribute \"%s\" not recognized", defel->defname))); } }
/* * CREATE TEXT SEARCH PARSER */ Oid DefineTSParser(List *names, List *parameters) { char *prsname; ListCell *pl; Relation prsRel; HeapTuple tup; Datum values[Natts_pg_ts_parser]; bool nulls[Natts_pg_ts_parser]; NameData pname; Oid prsOid; Oid namespaceoid; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create text search parsers"))); /* Convert list of names to a name and namespace */ namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname); /* initialize tuple fields with name/namespace */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); namestrcpy(&pname, prsname); values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname); values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid); /* * loop over the definition list and extract the information we need. */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); if (pg_strcasecmp(defel->defname, "start") == 0) { values[Anum_pg_ts_parser_prsstart - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart); } else if (pg_strcasecmp(defel->defname, "gettoken") == 0) { values[Anum_pg_ts_parser_prstoken - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken); } else if (pg_strcasecmp(defel->defname, "end") == 0) { values[Anum_pg_ts_parser_prsend - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsend); } else if (pg_strcasecmp(defel->defname, "headline") == 0) { values[Anum_pg_ts_parser_prsheadline - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline); } else if (pg_strcasecmp(defel->defname, "lextypes") == 0) { values[Anum_pg_ts_parser_prslextype - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("text search parser parameter \"%s\" not recognized", defel->defname))); }
/* * DefineOperator * this function extracts all the information from the * parameter list generated by the parser and then has * OperatorCreate() do all the actual work. * * 'parameters' is a list of DefElem */ void DefineOperator(List *names, List *parameters) { char *oprName; Oid oprNamespace; AclResult aclresult; bool canMerge = false; /* operator merges */ bool canHash = false; /* operator hashes */ List *functionName = NIL; /* function for operator */ TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName2 = NULL; /* second type name */ Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId2 = InvalidOid; Oid rettype; List *commutatorName = NIL; /* optional commutator operator name */ List *negatorName = NIL; /* optional negator operator name */ List *restrictionName = NIL; /* optional restrict. sel. procedure */ List *joinName = NIL; /* optional join sel. procedure */ Oid functionOid; /* functions converted to OID */ Oid restrictionOid; Oid joinOid; Oid typeId[5]; /* only need up to 5 args here */ int nargs; ListCell *pl; /* Convert list of names to a name and namespace */ oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName); /* * The SQL standard committee has decided that => should be used for named * parameters; therefore, a future release of PostgreSQL may disallow it * as the name of a user-defined operator. */ if (strcmp(oprName, "=>") == 0) ereport(WARNING, (errmsg("=> is deprecated as an operator name"), errdetail("This name may be disallowed altogether in future versions of PostgreSQL."))); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(oprNamespace)); /* * loop over the definition list and extract the information we need. */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); if (pg_strcasecmp(defel->defname, "leftarg") == 0) { typeName1 = defGetTypeName(defel); if (typeName1->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SETOF type not allowed for operator argument"))); } else if (pg_strcasecmp(defel->defname, "rightarg") == 0) { typeName2 = defGetTypeName(defel); if (typeName2->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SETOF type not allowed for operator argument"))); } else if (pg_strcasecmp(defel->defname, "procedure") == 0) functionName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "commutator") == 0) commutatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "negator") == 0) negatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "restrict") == 0) restrictionName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "join") == 0) joinName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "hashes") == 0) canHash = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "merges") == 0) canMerge = defGetBoolean(defel); /* These obsolete options are taken as meaning canMerge */ else if (pg_strcasecmp(defel->defname, "sort1") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "sort2") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "ltcmp") == 0) canMerge = true; else if (pg_strcasecmp(defel->defname, "gtcmp") == 0) canMerge = true; else ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("operator attribute \"%s\" not recognized", defel->defname))); }
/* * Examine the RETURNS clause of the CREATE FUNCTION statement * and return information about it as *prorettype_p and *returnsSet. * * This is more complex than the average typename lookup because we want to * allow a shell type to be used, or even created if the specified return type * doesn't exist yet. (Without this, there's no way to define the I/O procs * for a new type.) But SQL function creation won't cope, so error out if * the target language is SQL. (We do this here, not in the SQL-function * validator, so as not to produce a NOTICE and then an ERROR for the same * condition.) */ static void compute_return_type(TypeName *returnType, Oid languageOid, Oid *prorettype_p, bool *returnsSet_p) { Oid rettype; Type typtup; AclResult aclresult; typtup = LookupTypeName(NULL, returnType, NULL, false); if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { if (languageOid == SQLlanguageId) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot return shell type %s", TypeNameToString(returnType)))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("return type %s is only a shell", TypeNameToString(returnType)))); } rettype = typeTypeId(typtup); ReleaseSysCache(typtup); } else { char *typnam = TypeNameToString(returnType); Oid namespaceId; AclResult aclresult; char *typname; /* * Only C-coded functions can be I/O functions. We enforce this * restriction here mainly to prevent littering the catalogs with * shell types due to simple typos in user-defined function * definitions. */ if (languageOid != INTERNALlanguageId && languageOid != ClanguageId) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", typnam))); /* Reject if there's typmod decoration, too */ if (returnType->typmods != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type modifier cannot be specified for shell type \"%s\"", typnam))); /* Otherwise, go ahead and make a shell type */ ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" is not yet defined", typnam), errdetail("Creating a shell type definition."))); namespaceId = QualifiedNameGetCreationNamespace(returnType->names, &typname); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); rettype = TypeShellMake(typname, namespaceId, GetUserId()); Assert(OidIsValid(rettype)); } aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error_type(aclresult, rettype); *prorettype_p = rettype; *returnsSet_p = returnType->setof; }
/* * DefineFileSystem */ void DefineFileSystem(List *name, List *parameters, Oid newOid, bool trusted) { char *fsysName; Oid fsysNamespace; AclResult aclresult; List *funcNames[FSYS_FUNC_TOTALNUM]; char *fsysLibFile = NULL; int funcNum = 0; ListCell *pl; Oid fsysOid; /* Convert list of names to a name and namespace */ fsysNamespace = QualifiedNameGetCreationNamespace(name, &fsysName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(fsysNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(fsysNamespace)); for(int i = 0; i < FSYS_FUNC_TOTALNUM; i++) funcNames[i] = NIL; foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); int funcType; if (pg_strcasecmp(defel->defname, fsysLibFileName) == 0) { if(fsysLibFile == NULL) { fsysLibFile = strVal(linitial(defGetQualifiedName(defel))); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem attribute \"%s\" duplicated", defel->defname))); } continue; } for(funcType = 0; funcType < FSYS_FUNC_TOTALNUM; funcType++) { if(pg_strcasecmp(defel->defname, fsys_func_type_to_name(funcType)) == 0) break; } if (funcType >= FSYS_FUNC_TOTALNUM) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem attribute \"%s\" not recognized", defel->defname))); if(funcNames[funcType] == NIL) funcNames[funcType] = defGetQualifiedName(defel); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem function \"%s\" duplicated", defel->defname))); funcNum++; }
/* * DefineOperator * this function extracts all the information from the * parameter list generated by the parser and then has * OperatorCreate() do all the actual work. * * 'parameters' is a list of DefElem */ void DefineOperator(List *names, List *parameters) { char *oprName; Oid oprNamespace; AclResult aclresult; bool canHash = false; /* operator hashes */ bool canMerge = false; /* operator merges */ List *functionName = NIL; /* function for operator */ TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName2 = NULL; /* second type name */ Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId2 = InvalidOid; List *commutatorName = NIL; /* optional commutator operator * name */ List *negatorName = NIL; /* optional negator operator name */ List *restrictionName = NIL; /* optional restrict. sel. * procedure */ List *joinName = NIL; /* optional join sel. procedure */ List *leftSortName = NIL; /* optional left sort operator */ List *rightSortName = NIL; /* optional right sort operator */ List *ltCompareName = NIL; /* optional < compare operator */ List *gtCompareName = NIL; /* optional > compare operator */ List *pl; /* Convert list of names to a name and namespace */ oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(oprNamespace)); /* * loop over the definition list and extract the information we need. */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); if (strcasecmp(defel->defname, "leftarg") == 0) { typeName1 = defGetTypeName(defel); if (typeName1->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("setof type not allowed for operator argument"))); } else if (strcasecmp(defel->defname, "rightarg") == 0) { typeName2 = defGetTypeName(defel); if (typeName2->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("setof type not allowed for operator argument"))); } else if (strcasecmp(defel->defname, "procedure") == 0) functionName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "commutator") == 0) commutatorName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "negator") == 0) negatorName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "restrict") == 0) restrictionName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "join") == 0) joinName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "hashes") == 0) canHash = TRUE; else if (strcasecmp(defel->defname, "merges") == 0) canMerge = TRUE; else if (strcasecmp(defel->defname, "sort1") == 0) leftSortName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "sort2") == 0) rightSortName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "ltcmp") == 0) ltCompareName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "gtcmp") == 0) gtCompareName = defGetQualifiedName(defel); else ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("operator attribute \"%s\" not recognized", defel->defname))); }