]> granicus.if.org Git - postgresql/commitdiff
Allow ALTER FUNCTION to change a function's strictness, volatility, and
authorNeil Conway <neilc@samurai.com>
Mon, 14 Mar 2005 00:19:37 +0000 (00:19 +0000)
committerNeil Conway <neilc@samurai.com>
Mon, 14 Mar 2005 00:19:37 +0000 (00:19 +0000)
whether or not it is a security definer. Changing a function's strictness
is required by SQL2003, and the other capabilities make sense. Also, allow
an optional RESTRICT noise word to be specified, for SQL conformance.

Some trivial regression tests added and the documentation has been
updated.

12 files changed:
doc/src/sgml/ref/alter_function.sgml
doc/src/sgml/ref/alter_index.sgml
src/backend/commands/functioncmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/tcop/utility.c
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/test/regress/expected/alter_table.out
src/test/regress/sql/alter_table.sql

index 00dfcac007abee773266deb5f54b8315634dec33..468aa2b2e2e7f0656dd899fa8306dfc797ad14e7 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -20,8 +20,15 @@ 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>
   
@@ -69,11 +76,65 @@ ALTER FUNCTION <replaceable>name</replaceable> ( [ <replaceable class="parameter
     <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>
@@ -104,9 +165,13 @@ ALTER FUNCTION sqrt(integer) OWNER TO joe;
   <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>
 
index 4ce4a6871cf924790d55db6ea83ac7102062a0b3..7ea1f2e97a5391c5665f25c570ed3d3b58cf3b76 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -20,10 +20,8 @@ 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:
 
index e2afbce10296e2e16b1491fd5ed95b4242735b91..cbe14d130beb6f097e19c45fde81e9f8af12fdad 100644 (file)
@@ -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
index 4acf02908b68c936e7ffc74614bd2a6d4b255180..92f7168ae9fbf4d3337636c41a5b5b056f71cfdb 100644 (file)
@@ -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;
index f80da7572b5270f03987a7752c82a828371444b7..cbd99dab7207787f992efcaa810722296cee2d36 100644 (file)
@@ -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;
index 69e70821970a305218bc61a3c39551fce1be2f87..a88262d432816afb3755be874688a8bbb01dc225 100644 (file)
@@ -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 */
+               ;
+
 
 /*****************************************************************************
  *
index 006f904f72e0648124f972e425dfb0ca2f7278e6..a3b946647ac6490c430831065bc034ee336f5ec4 100644 (file)
@@ -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;
index 30f576d78119afb30e84e5da7920fa0ee0525224..546e9f8dc0d14b959829ca63f2988f124de45cbe 100644 (file)
@@ -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);
index 291b1f281f257c89f621dcde1d07bb4e86f991fd..5d70180a0c5775dcbb2adc6b86427e47c7657efa 100644 (file)
@@ -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,
index cd3eb634d4a7919d01e393d65bf42b94c84243c8..8cf274b14ce1374a5151895b56d5f860247fcf48 100644 (file)
@@ -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
  * ----------------------
index fbb23a4b127c8bc314a2d1e789de028737b4a82e..b9edbc649d4fc0140238f14eb35666dd9cafbf27 100644 (file)
@@ -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)
+
index e6be119ff7d3c0fd51f60828c3f5d302a5920631..445fabf7e09375c2ae98d6ccd9c8f1e2f9cd6462 100644 (file)
@@ -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