Datum dxsyn_init(PG_FUNCTION_ARGS) { List *dictoptions = (List *) PG_GETARG_POINTER(0); DictSyn *d; ListCell *l; char *filename = NULL; d = (DictSyn *) palloc0(sizeof(DictSyn)); d->len = 0; d->syn = NULL; d->matchorig = true; d->keeporig = true; d->matchsynonyms = false; d->keepsynonyms = true; foreach(l, dictoptions) { DefElem *defel = (DefElem *) lfirst(l); if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0) { d->matchorig = defGetBoolean(defel); } else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0) { d->keeporig = defGetBoolean(defel); } else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0) { d->matchsynonyms = defGetBoolean(defel); } else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0) { d->keepsynonyms = defGetBoolean(defel); } else if (pg_strcasecmp(defel->defname, "RULES") == 0) { /* we can't read the rules before parsing all options! */ filename = defGetString(defel); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized xsyn parameter: \"%s\"", defel->defname))); } }
Datum dxsyn_init(PG_FUNCTION_ARGS) { List *dictoptions = (List *) PG_GETARG_POINTER(0); DictSyn *d; ListCell *l; d = (DictSyn *) palloc0(sizeof(DictSyn)); d->len = 0; d->syn = NULL; d->keeporig = true; foreach(l, dictoptions) { DefElem *defel = (DefElem *) lfirst(l); if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0) { d->keeporig = defGetBoolean(defel); } else if (pg_strcasecmp(defel->defname, "RULES") == 0) { read_dictionary(d, defGetString(defel)); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized xsyn parameter: \"%s\"", defel->defname))); } }
Datum dsynonym_init(PG_FUNCTION_ARGS) { List *dictoptions = (List *) PG_GETARG_POINTER(0); DictSyn *d; ListCell *l; char *filename = NULL; bool case_sensitive = false; tsearch_readline_state trst; char *starti, *starto, *end = NULL; int cur = 0; char *line = NULL; uint16 flags = 0; foreach(l, dictoptions) { DefElem *defel = (DefElem *) lfirst(l); if (pg_strcasecmp("Synonyms", defel->defname) == 0) filename = defGetString(defel); else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0) case_sensitive = defGetBoolean(defel); else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized synonym parameter: \"%s\"", defel->defname))); }
Datum dintdict_init(PG_FUNCTION_ARGS) { List *dictoptions = (List *) PG_GETARG_POINTER(0); DictInt *d; ListCell *l; d = (DictInt *) palloc0(sizeof(DictInt)); d->maxlen = 6; d->rejectlong = false; foreach(l, dictoptions) { DefElem *defel = (DefElem *) lfirst(l); if (pg_strcasecmp(defel->defname, "MAXLEN") == 0) { d->maxlen = atoi(defGetString(defel)); } else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0) { d->rejectlong = defGetBoolean(defel); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized intdict parameter: \"%s\"", defel->defname))); } }
static bool getBoolOption(List* options, char const* name, bool defaultValue) { ListCell *cell; foreach(cell, options) { DefElem *def = (DefElem *) lfirst(cell); if (strcmp(def->defname, name) == 0) { return defGetBoolean(def); } }
Datum dsimple_init(PG_FUNCTION_ARGS) { List *dictoptions = (List *) PG_GETARG_POINTER(0); DictSimple *d = (DictSimple *) palloc0(sizeof(DictSimple)); bool stoploaded = false, acceptloaded = false; ListCell *l; d->accept = true; /* default */ foreach(l, dictoptions) { DefElem *defel = (DefElem *) lfirst(l); if (pg_strcasecmp("StopWords", defel->defname) == 0) { if (stoploaded) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("multiple StopWords parameters"))); readstoplist(defGetString(defel), &d->stoplist, lowerstr); stoploaded = true; } else if (pg_strcasecmp("Accept", defel->defname) == 0) { if (acceptloaded) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("multiple Accept parameters"))); d->accept = defGetBoolean(defel); acceptloaded = true; } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized simple dictionary parameter: \"%s\"", defel->defname))); } }
/* * Validate the generic options given to a FOREIGN DATA WRAPPER, SERVER, * USER MAPPING or FOREIGN TABLE that uses file_fdw. * * Raise an ERROR if the option or its value is considered invalid. */ Datum file_fdw_validator(PG_FUNCTION_ARGS) { List *options_list = untransformRelOptions(PG_GETARG_DATUM(0)); Oid catalog = PG_GETARG_OID(1); char *filename = NULL; DefElem *force_not_null = NULL; List *other_options = NIL; ListCell *cell; /* * Only superusers are allowed to set options of a file_fdw foreign table. * This is because the filename is one of those options, and we don't want * non-superusers to be able to determine which file gets read. * * Putting this sort of permissions check in a validator is a bit of a * crock, but there doesn't seem to be any other place that can enforce * the check more cleanly. * * Note that the valid_options[] array disallows setting filename at any * options level other than foreign table --- otherwise there'd still be a * security hole. */ if (catalog == ForeignTableRelationId && !superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("only superuser can change options of a file_fdw foreign table"))); /* * Check that only options supported by file_fdw, and allowed for the * current object type, are given. */ foreach(cell, options_list) { DefElem *def = (DefElem *) lfirst(cell); if (!is_valid_option(def->defname, catalog)) { struct FileFdwOption *opt; StringInfoData buf; /* * Unknown option specified, complain about it. Provide a hint * with list of valid options for the object. */ initStringInfo(&buf); for (opt = valid_options; opt->optname; opt++) { if (catalog == opt->optcontext) appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->optname); } ereport(ERROR, (errcode(ERRCODE_FDW_INVALID_OPTION_NAME), errmsg("invalid option \"%s\"", def->defname), errhint("Valid options in this context are: %s", buf.data))); } /* * Separate out filename and force_not_null, since ProcessCopyOptions * won't accept them. (force_not_null only comes in a boolean * per-column flavor here.) */ if (strcmp(def->defname, "filename") == 0) { if (filename) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); filename = defGetString(def); } else if (strcmp(def->defname, "force_not_null") == 0) { if (force_not_null) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); force_not_null = def; /* Don't care what the value is, as long as it's a legal boolean */ (void) defGetBoolean(def); } else other_options = lappend(other_options, 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" 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))); }
/* * Check list of options and return things filled. * This includes check on option values. */ static void check_node_options(const char *node_name, List *options, char **node_host, int *node_port, char *node_type, bool *is_primary, bool *is_preferred) { ListCell *option; if (!options) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("No options specified"))); /* Filter options */ foreach(option, options) { DefElem *defel = (DefElem *) lfirst(option); if (strcmp(defel->defname, "port") == 0) { *node_port = defGetTypeLength(defel); if (*node_port < 1 || *node_port > 65535) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("port value is out of range"))); } else if (strcmp(defel->defname, "host") == 0) { *node_host = defGetString(defel); } else if (strcmp(defel->defname, "type") == 0) { char *type_loc; type_loc = defGetString(defel); if (strcmp(type_loc, "coordinator") != 0 && strcmp(type_loc, "datanode") != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("type value is incorrect, specify 'coordinator or 'datanode'"))); if (strcmp(type_loc, "coordinator") == 0) *node_type = PGXC_NODE_COORDINATOR; else *node_type = PGXC_NODE_DATANODE; } else if (strcmp(defel->defname, "primary") == 0) { *is_primary = defGetBoolean(defel); } else if (strcmp(defel->defname, "preferred") == 0) { *is_preferred = defGetBoolean(defel); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("incorrect option: %s", 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 */ 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))); } }
/* * Common option parsing function for CREATE and ALTER SUBSCRIPTION commands. * * Since not all options can be specified in both commands, this function * will report an error on options if the target output pointer is NULL to * accomodate that. */ static void parse_subscription_options(List *options, bool *connect, bool *enabled_given, bool *enabled, bool *create_slot, char **slot_name, bool *copy_data) { ListCell *lc; bool connect_given = false; bool create_slot_given = false; bool copy_data_given = false; if (connect) *connect = true; if (enabled) { *enabled_given = false; *enabled = true; } if (create_slot) *create_slot = true; if (slot_name) *slot_name = NULL; if (copy_data) *copy_data = true; /* Parse options */ foreach (lc, options) { DefElem *defel = (DefElem *) lfirst(lc); if (strcmp(defel->defname, "noconnect") == 0 && connect) { if (connect_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); connect_given = true; *connect = !defGetBoolean(defel); } else if (strcmp(defel->defname, "enabled") == 0 && enabled) { if (*enabled_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); *enabled_given = true; *enabled = defGetBoolean(defel); } else if (strcmp(defel->defname, "disabled") == 0 && enabled) { if (*enabled_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); *enabled_given = true; *enabled = !defGetBoolean(defel); } else if (strcmp(defel->defname, "create slot") == 0 && create_slot) { if (create_slot_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); create_slot_given = true; *create_slot = defGetBoolean(defel); } else if (strcmp(defel->defname, "nocreate slot") == 0 && create_slot) { if (create_slot_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); create_slot_given = true; *create_slot = !defGetBoolean(defel); } else if (strcmp(defel->defname, "slot name") == 0 && slot_name) { if (*slot_name) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); *slot_name = defGetString(defel); } else if (strcmp(defel->defname, "copy data") == 0 && copy_data) { if (copy_data_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); copy_data_given = true; *copy_data = defGetBoolean(defel); } else if (strcmp(defel->defname, "nocopy data") == 0 && copy_data) { if (copy_data_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); copy_data_given = true; *copy_data = !defGetBoolean(defel); } else elog(ERROR, "unrecognized option: %s", 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))); }
Datum ppg_fdw_validator(PG_FUNCTION_ARGS) { List *options_list = untransformRelOptions(PG_GETARG_DATUM(0)); Oid catalog = PG_GETARG_OID(1); ListCell *cell; /* Build our options lists if we didn't yet. */ InitPgFdwOptions(); /* * Check that only options supported by postgres_fdw, and allowed for the * current object type, are given. */ foreach(cell, options_list) { DefElem *def = (DefElem *) lfirst(cell); if (!is_valid_option(def->defname, catalog)) { /* * Unknown option specified, complain about it. Provide a hint * with list of valid options for the object. */ PgFdwOption *opt; StringInfoData buf; initStringInfo(&buf); for (opt = postgres_fdw_options; opt->keyword; opt++) { if (catalog == opt->optcontext) appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->keyword); } ereport(ERROR, (errcode(ERRCODE_FDW_INVALID_OPTION_NAME), errmsg("invalid option \"%s\"", def->defname), errhint("Valid options in this context are: %s", buf.data))); } /* * Validate option value, when we can do so without any context. */ if (strcmp(def->defname, "use_remote_estimate") == 0) { /* use_remote_estimate accepts only boolean values */ (void) defGetBoolean(def); } else if (strcmp(def->defname, "fdw_startup_cost") == 0 || strcmp(def->defname, "fdw_tuple_cost") == 0) { /* these must have a non-negative numeric value */ double val; char *endp; val = strtod(defGetString(def), &endp); if (*endp || val < 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a non-negative numeric value", def->defname))); } }