diff options
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 88 |
1 files changed, 85 insertions, 3 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 9a2f1a85b47..4f62e48d98f 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -479,6 +479,7 @@ compute_common_attribute(ParseState *pstate, List **set_items, DefElem **cost_item, DefElem **rows_item, + DefElem **support_item, DefElem **parallel_item) { if (strcmp(defel->defname, "volatility") == 0) @@ -537,6 +538,15 @@ compute_common_attribute(ParseState *pstate, *rows_item = defel; } + else if (strcmp(defel->defname, "support") == 0) + { + if (is_procedure) + goto procedure_error; + if (*support_item) + goto duplicate_error; + + *support_item = defel; + } else if (strcmp(defel->defname, "parallel") == 0) { if (is_procedure) @@ -635,6 +645,45 @@ update_proconfig_value(ArrayType *a, List *set_items) return a; } +static Oid +interpret_func_support(DefElem *defel) +{ + List *procName = defGetQualifiedName(defel); + Oid procOid; + Oid argList[1]; + + /* + * Support functions always take one INTERNAL argument and return + * INTERNAL. + */ + argList[0] = INTERNALOID; + + procOid = LookupFuncName(procName, 1, argList, true); + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procName, 1, NIL, argList)))); + + if (get_func_rettype(procOid) != INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("support function %s must return type %s", + NameListToString(procName), "internal"))); + + /* + * Someday we might want an ACL check here; but for now, we insist that + * you be superuser to specify a support function, so privilege on the + * support function is moot. + */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to specify a support function"))); + + return procOid; +} + /* * Dissect the list of options assembled in gram.y into function @@ -655,6 +704,7 @@ compute_function_attributes(ParseState *pstate, ArrayType **proconfig, float4 *procost, float4 *prorows, + Oid *prosupport, char *parallel_p) { ListCell *option; @@ -669,6 +719,7 @@ compute_function_attributes(ParseState *pstate, List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; + DefElem *support_item = NULL; DefElem *parallel_item = NULL; foreach(option, options) @@ -726,6 +777,7 @@ compute_function_attributes(ParseState *pstate, &set_items, &cost_item, &rows_item, + &support_item, ¶llel_item)) { /* recognized common option */ @@ -788,6 +840,8 @@ compute_function_attributes(ParseState *pstate, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ROWS must be positive"))); } + if (support_item) + *prosupport = interpret_func_support(support_item); if (parallel_item) *parallel_p = interpret_func_parallel(parallel_item); } @@ -893,6 +947,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) ArrayType *proconfig; float4 procost; float4 prorows; + Oid prosupport; HeapTuple languageTuple; Form_pg_language languageStruct; List *as_clause; @@ -917,6 +972,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) proconfig = NULL; procost = -1; /* indicates not set */ prorows = -1; /* indicates not set */ + prosupport = InvalidOid; parallel = PROPARALLEL_UNSAFE; /* Extract non-default attributes from stmt->options list */ @@ -926,7 +982,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) &as_clause, &language, &transformDefElem, &isWindowFunc, &volatility, &isStrict, &security, &isLeakProof, - &proconfig, &procost, &prorows, ¶llel); + &proconfig, &procost, &prorows, + &prosupport, ¶llel); /* Look up the language and validate permissions */ languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language)); @@ -1113,6 +1170,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) parameterDefaults, PointerGetDatum(trftypes), PointerGetDatum(proconfig), + prosupport, procost, prorows); } @@ -1187,6 +1245,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; + DefElem *support_item = NULL; DefElem *parallel_item = NULL; ObjectAddress address; @@ -1194,6 +1253,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false); + ObjectAddressSet(address, ProcedureRelationId, funcOid); + tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid)); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", funcOid); @@ -1228,6 +1289,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) &set_items, &cost_item, &rows_item, + &support_item, ¶llel_item) == false) elog(ERROR, "option \"%s\" not recognized", defel->defname); } @@ -1266,6 +1328,28 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ROWS is not applicable when function does not return a set"))); } + if (support_item) + { + /* interpret_func_support handles the privilege check */ + Oid newsupport = interpret_func_support(support_item); + + /* Add or replace dependency on support function */ + if (OidIsValid(procForm->prosupport)) + changeDependencyFor(ProcedureRelationId, funcOid, + ProcedureRelationId, procForm->prosupport, + newsupport); + else + { + ObjectAddress referenced; + + referenced.classId = ProcedureRelationId; + referenced.objectId = newsupport; + referenced.objectSubId = 0; + recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL); + } + + procForm->prosupport = newsupport; + } if (set_items) { Datum datum; @@ -1308,8 +1392,6 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0); - ObjectAddressSet(address, ProcedureRelationId, funcOid); - table_close(rel, NoLock); heap_freetuple(tup); |