diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-09-03 00:39:26 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-09-03 00:39:26 +0000 |
commit | 2abae34a2e8fde42be731b4e18d44cd08901464d (patch) | |
tree | f555c8fc5d653c24ccc407a06f46e5f1bbbf40f7 /src/backend/commands/functioncmds.c | |
parent | fcfe801ab84c124d4103f9afb1140c9c2558cb54 (diff) | |
download | postgresql-2abae34a2e8fde42be731b4e18d44cd08901464d.tar.gz postgresql-2abae34a2e8fde42be731b4e18d44cd08901464d.zip |
Implement function-local GUC parameter settings, as per recent discussion.
There are still some loose ends: I didn't do anything about the SET FROM
CURRENT idea yet, and it's not real clear whether we are happy with the
interaction of SET LOCAL with function-local settings. The documentation
is a bit spartan, too.
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 107 |
1 files changed, 103 insertions, 4 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 0949feab1f2..a6768ab83c2 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.83 2007/04/02 03:49:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.84 2007/09/03 00:39:15 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -50,10 +50,14 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" -static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId); + +static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup, + Oid newOwnerId); + /* * Examine the RETURNS clause of the CREATE FUNCTION statement @@ -267,13 +271,15 @@ examine_parameter_list(List *parameters, Oid languageOid, * FUNCTION and ALTER FUNCTION and return it via one of the out * parameters. Returns true if the passed option was recognized. If * the out parameter we were going to assign to points to non-NULL, - * raise a duplicate error. + * raise a duplicate-clause error. (We don't try to detect duplicate + * SET parameters though --- if you're redundant, the last one wins.) */ static bool compute_common_attribute(DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, + List **set_items, DefElem **cost_item, DefElem **rows_item) { @@ -298,6 +304,10 @@ compute_common_attribute(DefElem *defel, *security_item = defel; } + else if (strcmp(defel->defname, "set") == 0) + { + *set_items = lappend(*set_items, defel->arg); + } else if (strcmp(defel->defname, "cost") == 0) { if (*cost_item) @@ -344,6 +354,51 @@ interpret_func_volatility(DefElem *defel) } /* + * Update a proconfig value according to a list of SET and RESET items. + * + * The input and result may be NULL to signify a null entry. + */ +static ArrayType * +update_proconfig_value(ArrayType *a, List *set_items) +{ + ListCell *l; + + foreach(l, set_items) + { + Node *sitem = (Node *) lfirst(l); + + if (IsA(sitem, VariableSetStmt)) + { + VariableSetStmt *sstmt = (VariableSetStmt *) sitem; + + if (sstmt->args) + { + char *valuestr; + + valuestr = flatten_set_variable_args(sstmt->name, sstmt->args); + a = GUCArrayAdd(a, sstmt->name, valuestr); + } + else /* SET TO DEFAULT */ + a = GUCArrayDelete(a, sstmt->name); + } + else if (IsA(sitem, VariableResetStmt)) + { + VariableResetStmt *rstmt = (VariableResetStmt *) sitem; + + if (strcmp(rstmt->name, "all") == 0) + a = NULL; /* RESET ALL */ + else + a = GUCArrayDelete(a, rstmt->name); + } + else + elog(ERROR, "unexpected node type: %d", nodeTag(sitem)); + } + + return a; +} + + +/* * Dissect the list of options assembled in gram.y into function * attributes. */ @@ -354,6 +409,7 @@ compute_attributes_sql_style(List *options, char *volatility_p, bool *strict_p, bool *security_definer, + ArrayType **proconfig, float4 *procost, float4 *prorows) { @@ -363,6 +419,7 @@ compute_attributes_sql_style(List *options, DefElem *volatility_item = NULL; DefElem *strict_item = NULL; DefElem *security_item = NULL; + List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; @@ -390,6 +447,7 @@ compute_attributes_sql_style(List *options, &volatility_item, &strict_item, &security_item, + &set_items, &cost_item, &rows_item)) { @@ -429,6 +487,8 @@ compute_attributes_sql_style(List *options, *strict_p = intVal(strict_item->arg); if (security_item) *security_definer = intVal(security_item->arg); + if (set_items) + *proconfig = update_proconfig_value(NULL, set_items); if (cost_item) { *procost = defGetNumeric(cost_item); @@ -557,6 +617,7 @@ CreateFunction(CreateFunctionStmt *stmt) bool isStrict, security; char volatility; + ArrayType *proconfig; float4 procost; float4 prorows; HeapTuple languageTuple; @@ -577,6 +638,7 @@ CreateFunction(CreateFunctionStmt *stmt) isStrict = false; security = false; volatility = PROVOLATILE_VOLATILE; + proconfig = NULL; procost = -1; /* indicates not set */ prorows = -1; /* indicates not set */ @@ -584,7 +646,7 @@ CreateFunction(CreateFunctionStmt *stmt) compute_attributes_sql_style(stmt->options, &as_clause, &language, &volatility, &isStrict, &security, - &procost, &prorows); + &proconfig, &procost, &prorows); /* Convert language name to canonical case */ languageName = case_translate_language_name(language); @@ -736,6 +798,7 @@ CreateFunction(CreateFunctionStmt *stmt) PointerGetDatum(allParameterTypes), PointerGetDatum(parameterModes), PointerGetDatum(parameterNames), + PointerGetDatum(proconfig), procost, prorows); } @@ -1084,6 +1147,7 @@ AlterFunction(AlterFunctionStmt *stmt) DefElem *volatility_item = NULL; DefElem *strict_item = NULL; DefElem *security_def_item = NULL; + List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; @@ -1121,6 +1185,7 @@ AlterFunction(AlterFunctionStmt *stmt) &volatility_item, &strict_item, &security_def_item, + &set_items, &cost_item, &rows_item) == false) elog(ERROR, "option \"%s\" not recognized", defel->defname); @@ -1152,6 +1217,40 @@ AlterFunction(AlterFunctionStmt *stmt) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ROWS is not applicable when function does not return a set"))); } + if (set_items) + { + Datum datum; + bool isnull; + ArrayType *a; + Datum repl_val[Natts_pg_proc]; + char repl_null[Natts_pg_proc]; + char repl_repl[Natts_pg_proc]; + + /* extract existing proconfig setting */ + datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull); + a = isnull ? NULL : DatumGetArrayTypeP(datum); + + /* update according to each SET or RESET item, left to right */ + a = update_proconfig_value(a, set_items); + + /* update the tuple */ + memset(repl_repl, ' ', sizeof(repl_repl)); + repl_repl[Anum_pg_proc_proconfig - 1] = 'r'; + + if (a == NULL) + { + repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0; + repl_null[Anum_pg_proc_proconfig - 1] = 'n'; + } + else + { + repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a); + repl_null[Anum_pg_proc_proconfig - 1] = ' '; + } + + tup = heap_modifytuple(tup, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + } /* Do the update */ simple_heap_update(rel, &tup->t_self, tup); |