diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/functioncmds.c | 181 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 16 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 14 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 84 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 12 | ||||
-rw-r--r-- | src/include/commands/defrem.h | 3 | ||||
-rw-r--r-- | src/include/nodes/nodes.h | 3 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 9 | ||||
-rw-r--r-- | src/test/regress/expected/alter_table.out | 35 | ||||
-rw-r--r-- | src/test/regress/sql/alter_table.sql | 17 |
10 files changed, 307 insertions, 67 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index e2afbce1029..cbe14d130be 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -3,14 +3,14 @@ * functioncmds.c * * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP - * CAST commands. + * CAST commands. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.55 2005/03/13 05:19:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.56 2005/03/14 00:19:36 neilc Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -195,12 +195,75 @@ examine_parameter_list(List *parameter, Oid languageOid, return parameterCount; } +/* + * Recognize one of the options that can be passed to both CREATE + * 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. + */ +static bool +compute_common_attribute(DefElem *defel, + DefElem **volatility_item, + DefElem **strict_item, + DefElem **security_item) +{ + if (strcmp(defel->defname, "volatility") == 0) + { + if (*volatility_item) + goto duplicate_error; + + *volatility_item = defel; + } + else if (strcmp(defel->defname, "strict") == 0) + { + if (*strict_item) + goto duplicate_error; + + *strict_item = defel; + } + else if (strcmp(defel->defname, "security") == 0) + { + if (*security_item) + goto duplicate_error; + + *security_item = defel; + } + else + return false; + + /* Recognized an option */ + return true; + +duplicate_error: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + return false; /* keep compiler quiet */ +} + +static char +interpret_func_volatility(DefElem *defel) +{ + char *str = strVal(defel->arg); + + if (strcmp(str, "immutable") == 0) + return PROVOLATILE_IMMUTABLE; + else if (strcmp(str, "stable") == 0) + return PROVOLATILE_STABLE; + else if (strcmp(str, "volatile") == 0) + return PROVOLATILE_VOLATILE; + else + { + elog(ERROR, "invalid volatility \"%s\"", str); + return 0; /* keep compiler quiet */ + } +} /* * Dissect the list of options assembled in gram.y into function * attributes. */ - static void compute_attributes_sql_style(List *options, List **as, @@ -236,29 +299,13 @@ compute_attributes_sql_style(List *options, errmsg("conflicting or redundant options"))); language_item = defel; } - else if (strcmp(defel->defname, "volatility") == 0) + else if (compute_common_attribute(defel, + &volatility_item, + &strict_item, + &security_item)) { - if (volatility_item) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - volatility_item = defel; - } - else if (strcmp(defel->defname, "strict") == 0) - { - if (strict_item) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - strict_item = defel; - } - else if (strcmp(defel->defname, "security") == 0) - { - if (security_item) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - security_item = defel; + /* recognized common option */ + continue; } else elog(ERROR, "option \"%s\" not recognized", @@ -280,18 +327,7 @@ compute_attributes_sql_style(List *options, errmsg("no language specified"))); if (volatility_item) - { - if (strcmp(strVal(volatility_item->arg), "immutable") == 0) - *volatility_p = PROVOLATILE_IMMUTABLE; - else if (strcmp(strVal(volatility_item->arg), "stable") == 0) - *volatility_p = PROVOLATILE_STABLE; - else if (strcmp(strVal(volatility_item->arg), "volatile") == 0) - *volatility_p = PROVOLATILE_VOLATILE; - else - elog(ERROR, "invalid volatility \"%s\"", - strVal(volatility_item->arg)); - } - + *volatility_p = interpret_func_volatility(volatility_item); if (strict_item) *strict_p = intVal(strict_item->arg); if (security_item) @@ -301,7 +337,7 @@ compute_attributes_sql_style(List *options, /*------------- * Interpret the parameters *parameters and return their contents via - * out parameters *isStrict_p and *volatility_p. + * *isStrict_p and *volatility_p. * * These parameters supply optional information about a function. * All have defaults if not specified. Parameters: @@ -347,9 +383,7 @@ compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatili * In all other cases * * AS <object reference, or sql code> - * */ - static void interpret_AS_clause(Oid languageOid, const char *languageName, List *as, char **prosrc_str_p, char **probin_str_p) @@ -799,7 +833,74 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId) heap_close(rel, NoLock); } +/* + * Implements the ALTER FUNCTION utility command (except for the + * RENAME and OWNER clauses, which are handled as part of the generic + * ALTER framework). + */ +void +AlterFunction(AlterFunctionStmt *stmt) +{ + HeapTuple tup; + Oid funcOid; + Form_pg_proc procForm; + Relation rel; + ListCell *l; + DefElem *volatility_item = NULL; + DefElem *strict_item = NULL; + DefElem *security_def_item = NULL; + + rel = heap_openr(ProcedureRelationName, RowExclusiveLock); + + funcOid = LookupFuncNameTypeNames(stmt->func->funcname, + stmt->func->funcargs, + false); + + tup = SearchSysCacheCopy(PROCOID, + ObjectIdGetDatum(funcOid), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for function %u", funcOid); + + procForm = (Form_pg_proc) GETSTRUCT(tup); + /* Permission check: must own function */ + if (!pg_proc_ownercheck(funcOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameListToString(stmt->func->funcname)); + + if (procForm->proisagg) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is an aggregate function", + NameListToString(stmt->func->funcname)))); + + /* Examine requested actions. */ + foreach (l, stmt->actions) + { + DefElem *defel = (DefElem *) lfirst(l); + + if (compute_common_attribute(defel, + &volatility_item, + &strict_item, + &security_def_item) == false) + elog(ERROR, "option \"%s\" not recognized", defel->defname); + } + + if (volatility_item) + procForm->provolatile = interpret_func_volatility(volatility_item); + if (strict_item) + procForm->proisstrict = intVal(strict_item->arg); + if (security_def_item) + procForm->prosecdef = intVal(security_def_item->arg); + + /* Do the update */ + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + heap_close(rel, NoLock); + heap_freetuple(tup); +} /* * SetFunctionReturnType - change declared return type of a function diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 4acf02908b6..92f7168ae9f 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.297 2005/03/10 23:21:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.298 2005/03/14 00:19:36 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -1892,6 +1892,17 @@ _copyFunctionParameter(FunctionParameter *from) return newnode; } +static AlterFunctionStmt * +_copyAlterFunctionStmt(AlterFunctionStmt *from) +{ + AlterFunctionStmt *newnode = makeNode(AlterFunctionStmt); + + COPY_NODE_FIELD(func); + COPY_NODE_FIELD(actions); + + return newnode; +} + static RemoveAggrStmt * _copyRemoveAggrStmt(RemoveAggrStmt *from) { @@ -2882,6 +2893,9 @@ copyObject(void *from) case T_FunctionParameter: retval = _copyFunctionParameter(from); break; + case T_AlterFunctionStmt: + retval = _copyAlterFunctionStmt(from); + break; case T_RemoveAggrStmt: retval = _copyRemoveAggrStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f80da7572b5..cbd99dab720 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.236 2005/03/10 23:21:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.237 2005/03/14 00:19:36 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -954,6 +954,15 @@ _equalFunctionParameter(FunctionParameter *a, FunctionParameter *b) } static bool +_equalAlterFunctionStmt(AlterFunctionStmt *a, AlterFunctionStmt *b) +{ + COMPARE_NODE_FIELD(func); + COMPARE_NODE_FIELD(actions); + + return true; +} + +static bool _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b) { COMPARE_NODE_FIELD(aggname); @@ -2014,6 +2023,9 @@ equal(void *a, void *b) case T_FunctionParameter: retval = _equalFunctionParameter(a, b); break; + case T_AlterFunctionStmt: + retval = _equalAlterFunctionStmt(a, b); + break; case T_RemoveAggrStmt: retval = _equalRemoveAggrStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 69e70821970..a88262d4328 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.483 2005/02/02 06:36:01 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.484 2005/03/14 00:19:36 neilc Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -142,7 +142,7 @@ static void doNegateFloat(Value *v); DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt - CreateFunctionStmt ReindexStmt RemoveAggrStmt + CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RuleActionStmt RuleActionStmtOrEmpty RuleStmt SelectStmt TransactionStmt TruncateStmt @@ -213,7 +213,7 @@ static void doNegateFloat(Value *v); %type <list> stmtblock stmtmulti OptTableElementList TableElementList OptInherit definition opt_distinct opt_definition func_args - func_args_list func_as createfunc_opt_list + func_args_list func_as createfunc_opt_list alterfunc_opt_list oper_argtypes RuleActionList RuleActionMulti opt_column_list columnList opt_name_list sort_clause opt_sort_clause sortby_list index_params @@ -231,7 +231,7 @@ static void doNegateFloat(Value *v); %type <range> into_clause OptTempTableName -%type <defelt> createfunc_opt_item +%type <defelt> createfunc_opt_item common_func_opt_item %type <fun_param> func_arg %type <typnam> func_return func_type aggr_argtype @@ -486,6 +486,7 @@ stmtmulti: stmtmulti ';' stmt stmt : AlterDatabaseSetStmt | AlterDomainStmt + | AlterFunctionStmt | AlterGroupStmt | AlterOwnerStmt | AlterSeqStmt @@ -3371,14 +3372,21 @@ createfunc_opt_list: | createfunc_opt_list createfunc_opt_item { $$ = lappend($1, $2); } ; -createfunc_opt_item: - AS func_as +/* + * Options common to both CREATE FUNCTION and ALTER FUNCTION + */ +common_func_opt_item: + CALLED ON NULL_P INPUT_P { - $$ = makeDefElem("as", (Node *)$2); + $$ = makeDefElem("strict", (Node *)makeInteger(FALSE)); } - | LANGUAGE ColId_or_Sconst + | RETURNS NULL_P ON NULL_P INPUT_P { - $$ = makeDefElem("language", (Node *)makeString($2)); + $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); + } + | STRICT_P + { + $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); } | IMMUTABLE { @@ -3392,18 +3400,7 @@ createfunc_opt_item: { $$ = makeDefElem("volatility", (Node *)makeString("volatile")); } - | CALLED ON NULL_P INPUT_P - { - $$ = makeDefElem("strict", (Node *)makeInteger(FALSE)); - } - | RETURNS NULL_P ON NULL_P INPUT_P - { - $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); - } - | STRICT_P - { - $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); - } + | EXTERNAL SECURITY DEFINER { $$ = makeDefElem("security", (Node *)makeInteger(TRUE)); @@ -3422,6 +3419,21 @@ createfunc_opt_item: } ; +createfunc_opt_item: + AS func_as + { + $$ = makeDefElem("as", (Node *)$2); + } + | LANGUAGE ColId_or_Sconst + { + $$ = makeDefElem("language", (Node *)makeString($2)); + } + | common_func_opt_item + { + $$ = $1; + } + ; + func_as: Sconst { $$ = list_make1(makeString($1)); } | Sconst ',' Sconst { @@ -3434,6 +3446,36 @@ opt_definition: | /*EMPTY*/ { $$ = NIL; } ; +/***************************************************************************** + * ALTER FUNCTION + * + * RENAME and OWNER subcommands are already provided by the generic + * ALTER infrastructure, here we just specify alterations that can + * only be applied to functions. + * + *****************************************************************************/ +AlterFunctionStmt: + ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict + { + AlterFunctionStmt *n = makeNode(AlterFunctionStmt); + n->func = (FuncWithArgs *) $3; + n->actions = $4; + $$ = (Node *) n; + } + ; + +alterfunc_opt_list: + /* At least one option must be specified */ + common_func_opt_item { $$ = list_make1($1); } + | alterfunc_opt_list common_func_opt_item { $$ = lappend($1, $2); } + ; + +/* Ignored, merely for SQL compliance */ +opt_restrict: + RESTRICT + | /* EMPTY */ + ; + /***************************************************************************** * diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 006f904f72e..a3b946647ac 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.233 2005/01/27 03:18:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.234 2005/03/14 00:19:36 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -277,6 +277,7 @@ check_xact_readonly(Node *parsetree) { case T_AlterDatabaseSetStmt: case T_AlterDomainStmt: + case T_AlterFunctionStmt: case T_AlterGroupStmt: case T_AlterOwnerStmt: case T_AlterSeqStmt: @@ -711,6 +712,10 @@ ProcessUtility(Node *parsetree, CreateFunction((CreateFunctionStmt *) parsetree); break; + case T_AlterFunctionStmt: /* ALTER FUNCTION */ + AlterFunction((AlterFunctionStmt *) parsetree); + break; + case T_IndexStmt: /* CREATE INDEX */ { IndexStmt *stmt = (IndexStmt *) parsetree; @@ -1394,10 +1399,15 @@ CreateCommandTag(Node *parsetree) tag = "ALTER TABLE"; } break; + case T_AlterDomainStmt: tag = "ALTER DOMAIN"; break; + case T_AlterFunctionStmt: + tag = "ALTER FUNCTION"; + break; + case T_GrantStmt: { GrantStmt *stmt = (GrantStmt *) parsetree; diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 30f576d7811..546e9f8dc0d 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.62 2004/12/31 22:03:28 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.63 2005/03/14 00:19:37 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ extern void SetFunctionReturnType(Oid funcOid, Oid newRetType); extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType); extern void RenameFunction(List *name, List *argtypes, const char *newname); extern void AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId); +extern void AlterFunction(AlterFunctionStmt *stmt); extern void CreateCast(CreateCastStmt *stmt); extern void DropCast(DropCastStmt *stmt); extern void DropCastById(Oid castOid); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 291b1f281f2..5d70180a0c5 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.163 2004/12/31 22:03:34 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.164 2005/03/14 00:19:37 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -223,6 +223,7 @@ typedef enum NodeTag T_FetchStmt, T_IndexStmt, T_CreateFunctionStmt, + T_AlterFunctionStmt, T_RemoveAggrStmt, T_RemoveFuncStmt, T_RemoveOperStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index cd3eb634d4a..8cf274b14ce 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.273 2005/03/10 23:21:24 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.274 2005/03/14 00:19:37 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -1397,6 +1397,13 @@ typedef struct FunctionParameter /* someday add IN/OUT/INOUT indicator here */ } FunctionParameter; +typedef struct AlterFunctionStmt +{ + NodeTag type; + FuncWithArgs *func; /* name and args of function */ + List *actions; /* list of DefElem */ +} AlterFunctionStmt; + /* ---------------------- * Drop Aggregate Statement * ---------------------- diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index fbb23a4b127..b9edbc649d4 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -1235,3 +1235,38 @@ select * from another; (3 rows) drop table another; +-- +-- alter function +-- +create function test_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql returns null on null input; +select test_strict(NULL); + test_strict +------------- + +(1 row) + +alter function test_strict(text) called on null input; +select test_strict(NULL); + test_strict +------------------- + got passed a null +(1 row) + +create function non_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql called on null input; +select non_strict(NULL); + non_strict +------------------- + got passed a null +(1 row) + +alter function non_strict(text) returns null on null input; +select non_strict(NULL); + non_strict +------------ + +(1 row) + diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index e6be119ff7d..445fabf7e09 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -975,3 +975,20 @@ alter table another select * from another; drop table another; + +-- +-- alter function +-- +create function test_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql returns null on null input; +select test_strict(NULL); +alter function test_strict(text) called on null input; +select test_strict(NULL); + +create function non_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql called on null input; +select non_strict(NULL); +alter function non_strict(text) returns null on null input; +select non_strict(NULL);
\ No newline at end of file |