<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.5 2004/06/25 21:55:50 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.6 2005/03/14 00:19:36 neilc Exp $
PostgreSQL documentation
-->
<refsynopsisdiv>
<synopsis>
+ALTER FUNCTION <replaceable>name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] ) <replaceable class="PARAMETER">action</replaceable> [, ... ] [ RESTRICT ]
ALTER FUNCTION <replaceable>name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] ) RENAME TO <replaceable>newname</replaceable>
ALTER FUNCTION <replaceable>name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] ) OWNER TO <replaceable>newowner</replaceable>
+
+where <replaceable class="PARAMETER">action</replaceable> is one of:
+
+ CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
+ IMMUTABLE | STABLE | VOLATILE
+ [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
</synopsis>
</refsynopsisdiv>
<term><replaceable class="parameter">newowner</replaceable></term>
<listitem>
<para>
- 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
- <literal>SECURITY DEFINER</literal>,
- 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 <literal>SECURITY DEFINER</literal>, it will subsequently
+ execute as the new owner.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>CALLED ON NULL INPUT</literal></term>
+ <term><literal>RETURNS NULL ON NULL INPUT</literal></term>
+ <term><literal>STRICT</literal></term>
+
+ <listitem>
+ <para>
+ <literal>CALLED ON NULL INPUT</literal> changes the function so
+ that it will be invoked when some or all of its arguments are
+ null. <literal>RETURNS NULL ON NULL INPUT</literal> or
+ <literal>STRICT</literal> changes the function so that it
+ always returns null if any of its arguments are null. See <xref
+ linkend="sql-createfunction"> for more information.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>IMMUTABLE</literal></term>
+ <term><literal>STABLE</literal></term>
+ <term><literal>VOLATILE</literal></term>
+
+ <listitem>
+ <para>
+ Change the volatility of the function to the specified
+ type. See <xref linkend="sql-createfunction"> for more
+ information about function volatility.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal><optional>EXTERNAL</optional> SECURITY INVOKER</literal></term>
+ <term><literal><optional>EXTERNAL</optional> SECURITY DEFINER</literal></term>
+
+ <listitem>
+ <para>
+ Change whether the function is a security definer or not. The
+ key word <literal>EXTERNAL</literal> is ignored for SQL
+ conformance. See <xref linkend="sql-createfunction"> for more
+ information about this capability.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RESTRICT</literal></term>
+
+ <listitem>
+ <para>
+ Ignored for conformance with the SQL standard.
</para>
</listitem>
</varlistentry>
<title>Compatibility</title>
<para>
- There is an <command>ALTER FUNCTION</command> 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 <command>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 <literal>RESTRICT</> key word; it is optional in
+ <productname>PostgreSQL</>.
</para>
</refsect1>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.4 2004/08/24 00:06:51 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.5 2005/03/14 00:19:36 neilc Exp $
PostgreSQL documentation
-->
<refsynopsisdiv>
<synopsis>
-ALTER INDEX <replaceable class="PARAMETER">name</replaceable>
- <replaceable class="PARAMETER">action</replaceable> [, ... ]
-ALTER INDEX <replaceable class="PARAMETER">name</replaceable>
- RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
+ALTER INDEX <replaceable class="PARAMETER">name</replaceable> <replaceable class="PARAMETER">action</replaceable> [, ... ]
+ALTER INDEX <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
where <replaceable class="PARAMETER">action</replaceable> is one of:
* 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
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,
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",
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)
/*-------------
* 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:
* 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)
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
{
case T_FunctionParameter:
retval = _copyFunctionParameter(from);
break;
+ case T_AlterFunctionStmt:
+ retval = _copyAlterFunctionStmt(from);
+ break;
case T_RemoveAggrStmt:
retval = _copyRemoveAggrStmt(from);
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
{
case T_FunctionParameter:
retval = _equalFunctionParameter(a, b);
break;
+ case T_AlterFunctionStmt:
+ retval = _equalAlterFunctionStmt(a, b);
+ break;
case T_RemoveAggrStmt:
retval = _equalRemoveAggrStmt(a, b);
break;
*
*
* 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
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
%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
%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
stmt :
AlterDatabaseSetStmt
| AlterDomainStmt
+ | AlterFunctionStmt
| AlterGroupStmt
| AlterOwnerStmt
| AlterSeqStmt
| 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
{
{
$$ = 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));
}
;
+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
{
| /*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 */
+ ;
+
/*****************************************************************************
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
case T_AlterDatabaseSetStmt:
case T_AlterDomainStmt:
+ case T_AlterFunctionStmt:
case T_AlterGroupStmt:
case T_AlterOwnerStmt:
case T_AlterSeqStmt:
CreateFunction((CreateFunctionStmt *) parsetree);
break;
+ case T_AlterFunctionStmt: /* ALTER FUNCTION */
+ AlterFunction((AlterFunctionStmt *) parsetree);
+ break;
+
case T_IndexStmt: /* CREATE INDEX */
{
IndexStmt *stmt = (IndexStmt *) 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;
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
T_FetchStmt,
T_IndexStmt,
T_CreateFunctionStmt,
+ T_AlterFunctionStmt,
T_RemoveAggrStmt,
T_RemoveFuncStmt,
T_RemoveOperStmt,
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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
* ----------------------
(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)
+
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