diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml index 00dfcac007..468aa2b2e2 100644 --- a/doc/src/sgml/ref/alter_function.sgml +++ b/doc/src/sgml/ref/alter_function.sgml @@ -1,5 +1,5 @@ @@ -20,8 +20,15 @@ PostgreSQL documentation +ALTER FUNCTION name ( [ type [, ...] ] ) action [, ... ] [ RESTRICT ] ALTER FUNCTION name ( [ type [, ...] ] ) RENAME TO newname ALTER FUNCTION name ( [ type [, ...] ] ) OWNER TO newowner + +where action is one of: + + CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT + IMMUTABLE | STABLE | VOLATILE + [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER @@ -69,11 +76,65 @@ ALTER FUNCTION name ( [ newowner - The new owner of the function. - To change the owner of a function, you must be a superuser. - Note that if the function is marked - SECURITY DEFINER, - it will subsequently execute as the new owner. + The new owner of the function. To change the owner of a + function, you must be a superuser. Note that if the function is + marked SECURITY DEFINER, it will subsequently + execute as the new owner. + + + + + + CALLED ON NULL INPUT + RETURNS NULL ON NULL INPUT + STRICT + + + + CALLED ON NULL INPUT changes the function so + that it will be invoked when some or all of its arguments are + null. RETURNS NULL ON NULL INPUT or + STRICT changes the function so that it + always returns null if any of its arguments are null. See for more information. + + + + + + IMMUTABLE + STABLE + VOLATILE + + + + Change the volatility of the function to the specified + type. See for more + information about function volatility. + + + + + + EXTERNAL SECURITY INVOKER + EXTERNAL SECURITY DEFINER + + + + Change whether the function is a security definer or not. The + key word EXTERNAL is ignored for SQL + conformance. See for more + information about this capability. + + + + + + RESTRICT + + + + Ignored for conformance with the SQL standard. @@ -104,9 +165,13 @@ ALTER FUNCTION sqrt(integer) OWNER TO joe; Compatibility - There is an ALTER FUNCTION statement in the SQL - standard, but it does not provide the option to rename the - function or change the owner. + This statement is partially compatible with the ALTER + FUNCTION statement in the SQL standard. The standard allows more + properties of a function to be modified, but does not provide the + ability to rename a function, make a function a security definer, + or change the owner or volatility of a function. The standard also + requires the RESTRICT key word; it is optional in + PostgreSQL. diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 4ce4a6871c..7ea1f2e97a 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -1,5 +1,5 @@ @@ -20,10 +20,8 @@ PostgreSQL documentation -ALTER INDEX name - action [, ... ] -ALTER INDEX name - RENAME TO new_name +ALTER INDEX name action [, ... ] +ALTER INDEX name RENAME TO new_name where action is one of: diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index e2afbce102..cbe14d130b 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 - * */ - 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 4acf02908b..92f7168ae9 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 f80da7572b..cbd99dab72 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 $ * *------------------------------------------------------------------------- */ @@ -953,6 +953,15 @@ _equalFunctionParameter(FunctionParameter *a, FunctionParameter *b) return true; } +static bool +_equalAlterFunctionStmt(AlterFunctionStmt *a, AlterFunctionStmt *b) +{ + COMPARE_NODE_FIELD(func); + COMPARE_NODE_FIELD(actions); + + return true; +} + static bool _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b) { @@ -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 69e7082197..a88262d432 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 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 into_clause OptTempTableName -%type createfunc_opt_item +%type createfunc_opt_item common_func_opt_item %type func_arg %type 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 006f904f72..a3b946647a 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 30f576d781..546e9f8dc0 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 291b1f281f..5d70180a0c 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 cd3eb634d4..8cf274b14c 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 fbb23a4b12..b9edbc649d 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 e6be119ff7..445fabf7e0 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