1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

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.
This commit is contained in:
Tom Lane
2007-09-03 00:39:26 +00:00
parent fcfe801ab8
commit 2abae34a2e
23 changed files with 2583 additions and 2151 deletions

View File

@ -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)
@ -343,6 +353,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);