Extend syntax of CREATE FUNCTION to resemble SQL99.
authorPeter Eisentraut
Fri, 17 May 2002 18:32:52 +0000 (18:32 +0000)
committerPeter Eisentraut
Fri, 17 May 2002 18:32:52 +0000 (18:32 +0000)
13 files changed:
doc/src/sgml/ref/create_function.sgml
doc/src/sgml/release.sgml
src/backend/commands/functioncmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/bin/pg_dump/pg_dump.c
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h

index 1896133653171aae1851824f0651316e9c4650d6..495a1331464b85f13f8cde4fa2d1977320fa08cb 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -17,13 +17,13 @@ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.37 2002/04/23
 
 CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] )
     RETURNS rettype
-    AS 'definition'
-    LANGUAGE langname
-    [ WITH ( attribute [, ...] ) ]
-CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] )
-    RETURNS rettype
-    AS 'obj_file', 'link_symbol'
-    LANGUAGE langname
+  { LANGUAGE langname
+    | IMMUTABLE | STABLE | VOLATILE
+    | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
+    | IMPLICIT CAST
+    | AS 'definition'
+    AS 'obj_file', 'link_symbol'
+  } ...
     [ WITH ( attribute [, ...] ) ]
 
  
@@ -33,8 +33,13 @@ CREATE [ OR REPLACE ] FUNCTION name
 
   
    CREATE FUNCTION defines a new function.
-   CREATE OR REPLACE FUNCTION will either create
-   a new function, or replace an existing definition.
+   CREATE OR REPLACE FUNCTION will either create a
+   new function, or replace an existing definition.
+  
+
+  
+   The user that creates the function becomes the owner of the function.
+  
 
    
     Parameters
@@ -81,7 +86,7 @@ CREATE [ OR REPLACE ] FUNCTION name
 
      
       
-       The return data type.  The output type may be specified as a
+       The return data type.  The return type may be specified as a
        base type, complex type, setof type,
        opaque, or the same as the type of an
        existing column.
@@ -95,6 +100,105 @@ CREATE [ OR REPLACE ] FUNCTION name
      
     
 
+    
+     langname
+
+     
+      
+       The name of the language that the function is implemented in.
+       May be SQLC,
+       internal, or the name of a user-defined
+       procedural language.  (See also 
+       endterm="app-createlang-title">.)  For backward compatibility,
+       the name may be enclosed by single quotes.
+      
+     
+    
+
+    
+     IMMUTABLE
+     STABLE
+     VOLATILE
+
+     
+      
+       These attributes inform the system whether it is safe to
+       replace multiple evaluations of the function with a single
+       evaluation, for run-time optimization.  At most one choice
+       should be specified.  If none of these appear,
+       VOLATILE is the default assumption.
+      
+
+      
+       IMMUTABLE indicates that the function always
+       returns the same result when given the same argument values; that
+       is, it does not do database lookups or otherwise use information not
+       directly present in its parameter list.  If this option is given,
+       any call of the function with all-constant arguments can be
+       immediately replaced with the function value.
+      
+
+      
+       STABLE indicates that within a single table scan
+       the function will consistently
+       return the same result for the same argument values, but that its
+       result could change across SQL statements.  This is the appropriate
+       selection for functions whose results depend on database lookups,
+       parameter variables (such as the current time zone), etc.  Also note
+       that the CURRENT_TIMESTAMP family of functions qualify
+       as stable, since their values do not change within a transaction.
+      
+
+      
+       VOLATILE indicates that the function value can
+       change even within a single table scan, so no optimizations can be
+       made.  Relatively few database functions are volatile in this sense;
+       some examples are random(), currval(),
+       timeofday().  Note that any function that has side-effects
+       must be classified volatile, even if its result is quite predictable,
+       to prevent calls from being optimized away; an example is
+       setval().
+      
+     
+    
+
+    
+     CALLED ON NULL INPUT
+     RETURNS NULL ON NULL INPUT
+     STRICT
+
+     
+      
+       CALLED ON NULL INPUT (the default) indicates
+       that the function will be called normally when some of its
+       arguments are null.  It is then the function author's
+       responsibility to check for NULLs if necessary and respond
+       appropriately.
+      
+
+      
+       RETURNS NULL ON NULL INPUT or
+       STRICT indicates that the function always
+       returns NULL whenever any of its arguments are NULL.  If this
+       parameter is specified, the function is not executed when there
+       are NULL arguments; instead a NULL result is assumed
+       automatically.
+      
+     
+    
+
+    
+     IMPLICIT CAST
+
+     
+      
+       Indicates that the function may be used for implicit type
+       conversions.  See 
+       endterm="sql-createfunction-cast-functions-title"> for more detail.
+      
+     
+    
+
     
      definition
 
@@ -125,116 +229,56 @@ CREATE [ OR REPLACE ] FUNCTION name
      
     
 
-    
-     langname
-
-     
-      
-       May be SQLC,
-       internal, or 
-       class="parameter">plname, where 
-       class="parameter">plname is the name of a
-       created procedural language. See
-       
-       for details.  For backward compatibility, the name may be
-       enclosed by single quotes.
-      
-     
-    
-
     
      attribute
 
      
       
-       An optional piece of information about the function, used for
-       optimization.  See below for details.
-      
-     
-    
+       The historical way to specify optional pieces of information
+       about the function.  The following attributes may appear here:
+
+      
+       
+        isStrict
+        
+         
+          Equivalent to STRICT or RETURNS NULL ON NULL INPUT
+         
+        
+       
+
+       
+        isImmutable
+        isCachable
+        isStable
+        isVolatile
+        
+         
+          Equivalent to IMMUTABLE,
+          STABLEVOLATILE.
+          isCachable is an obsolete equivalent of
+          isImmutable; it's still accepted for
+          backwards-compatibility reasons.
+         
+        
+       
+
+       
+        implicitCoercion
+        
+         
+          Same as IMPLICIT CAST
+         
+        
+       
+      
+
+      Attribute names are not case-sensitive.
+     
+    
+   
 
    
-  
-
-  
-   The user that creates the function becomes the owner of the function.
-  
-
-  
-    The following attributes may appear in the WITH clause:
-
-    
-     
-      isStrict
-      
-       
-    indicates that the function always
-   returns NULL whenever any of its arguments are NULL.  If this
-   attribute is specified, the function is not executed when there
-   are NULL arguments; instead a NULL result is assumed automatically.
-   When  is not specified, the function will
-   be called for NULL inputs.  It is then the function author's
-   responsibility to check for NULLs if necessary and respond
-   appropriately.
-       
-      
-     
-
-     
-      isImmutable
-      isCachable
-      isStable
-      isVolatile
-      
-       
-        These attributes inform the system whether it is safe to replace
-   multiple evaluations of the function with a single evaluation.
-   At most one choice should be specified.  (If none of these appear,
-    is the default assumption.)
-    indicates that the function always
-   returns the same result when given the same argument values; that
-   is, it does not do database lookups or otherwise use information not
-   directly present in its parameter list.  If this option is given,
-   any call of the function with all-constant arguments can be
-   immediately replaced with the function value.
-    is an
-   obsolete equivalent of ; it's still
-   accepted for backwards-compatibility reasons.
-    indicates that within a single table scan
-   the function will consistently
-   return the same result for the same argument values, but that its
-   result could change across SQL statements.  This is the appropriate
-   selection for functions whose results depend on database lookups,
-   parameter variables (such as the current timezone), etc.  Also note
-   that the CURRENT_TIMESTAMP family of functions qualify
-   as stable, since their values do not change within a transaction.
-    indicates that the function value can
-   change even within a single table scan, so no optimizations can be
-   made.  Relatively few database functions are volatile in this sense;
-   some examples are random(), currval(),
-   timeofday().  Note that any function that has side-effects
-   must be classified volatile, even if its result is quite predictable,
-   to prevent calls from being optimized away; an example is
-   setval().
-       
-      
-     
-
-     
-      implicitCoercion
-      
-       
-    indicates that the function 
-   may be used for implicit type conversions.
-   See 
-   endterm="coercion-functions-title"> for more detail.
-       
-      
-     
-    
-
-    Attribute names are not case-sensitive.
-  
 
  
 
@@ -328,21 +372,18 @@ CREATE [ OR REPLACE ] FUNCTION name
   
  
 
-  
-   2002-04-11
-  
-  
-   Type Coercion Functions
+  
+   Type Cast Functions
   
   
-   A function that has one parameter and is named the same as its output
-   datatype (including the schema name) is considered to be a type
-   coercion function: it can be invoked to convert a value of its input
-   datatype into a value 
+   A function that has one argument and is named the same as its return
+   data type (including the schema name) is considered to be a type
+   casting function: it can be invoked to convert a value of its input
+   data type into a value 
    of its output datatype.  For example,
 
-   SELECT CAST(42 AS text);
+SELECT CAST(42 AS text);
 
    converts the integer constant 42 to text by invoking a function
    text(int4), if such a function exists and returns type
@@ -350,31 +391,33 @@ CREATE [ OR REPLACE ] FUNCTION name
   
 
   
-   If a potential coercion function is marked implicitCoercion,
-   then it can be invoked in any context where the conversion it defines
-   is required.  Coercion functions not so marked can be invoked only by
-   explicit CAST,
-   x::typename,
-   or typename(x) constructs.
-   For example, supposing that foo.f1 is a column of type text, then
+   If a potential cast function is marked IMPLICIT CAST,
+   then it can be invoked implicitly in any context where the
+   conversion it defines is required.  Cast functions not so marked
+   can be invoked only by explicit CAST,
+   x::typename, or
+   typename(x) constructs.  For
+   example, supposing that foo.f1 is a column of
+   type text, then
 
-   INSERT INTO foo(f1) VALUES(42);
+INSERT INTO foo(f1) VALUES(42);
 
    will be allowed if text(int4) is marked
-   implicitCoercion, otherwise not.
+   IMPLICIT CAST, otherwise not.
   
 
   
-   It is wise to be conservative about marking coercion functions as
-   implicit coercions.  An overabundance of implicit coercion paths
-   can cause PostgreSQL to choose surprising
-   interpretations of commands, 
-   or to be unable to resolve commands at all because there are multiple
-   possible interpretations.  A good rule of thumb is to make coercions
-   implicitly invokable only for information-preserving transformations
-   between types in the same general type category.  For example, int2
-   to int4 coercion can reasonably be implicit, but be wary of marking
-   int4 to text or float8 to int4 as implicit coercions.
+   It is wise to be conservative about marking cast functions as
+   implicit casts.  An overabundance of implicit casting paths can
+   cause PostgreSQL to choose surprising
+   interpretations of commands, or to be unable to resolve commands at
+   all because there are multiple possible interpretations.  A good
+   rule of thumb is to make cast implicitly invokable only for
+   information-preserving transformations between types in the same
+   general type category.  For example, int2 to
+   int4 casts can reasonably be implicit, but be wary of
+   marking int4 to text or
+   float8 to int4 as implicit casts.
   
  
   
@@ -403,7 +446,7 @@ SELECT one() AS answer;
    user-created shared library named funcs.so (the extension
    may vary across platforms).  The shared library file is sought in the
    server's dynamic library search path.  This particular routine calculates
-   a check digit and returns TRUE if the check digit in the function
+   a check digit and returns true if the check digit in the function
    parameters is correct.  It is intended for use in a CHECK
    constraint.
 
@@ -422,7 +465,7 @@ CREATE TABLE product (
   
 
   
-   This example creates a function that does type conversion from the
+   The next example creates a function that does type conversion from the
    user-defined type complex to the built-in type point.  The
    function is implemented by a dynamically loaded object that was
    compiled from C source (we illustrate the now-deprecated alternative
@@ -436,7 +479,7 @@ CREATE TABLE product (
 
 CREATE FUNCTION point(complex) RETURNS point
     AS '/home/bernie/pgsql/lib/complex.so', 'complex_to_point'
-    LANGUAGE C WITH (isStrict);
+    LANGUAGE C STRICT;
 
 
   The C declaration of the function could be:
@@ -466,7 +509,7 @@ Point * complex_to_point (Complex *z)
   
    A CREATE FUNCTION command is defined in SQL99.
    The PostgreSQL version is similar but
-   not compatible.  The attributes are not portable, neither are the
+   not fully compatible.  The attributes are not portable, neither are the
    different available languages.
   
  
@@ -476,10 +519,11 @@ Point * complex_to_point (Complex *z)
   See Also
 
   
-   ,
-   ,
-   ,
-   ,
+   ,
+   ,
+   ,
+   ,
+   ,
    PostgreSQL Programmer's Guide
   
  
index 889f2203f6916a89bbc9638857cb71064d571486..9b75049938ad5c29040b586b191f10fd0f22a1c8 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 
+Syntax of CREATE FUNCTION has been extended to resemble SQL99
 Effects of SET within a transaction block now roll back if transaction aborts
 New SET LOCAL syntax sets a parameter for the life of the current transaction
 Datestyle, timezone, client_encoding can be set in postgresql.conf
index ce4b43b593682854cbeab5636bee54d1999b9c9f..e294b6f973e1e12be1144aa060bd6001a2bdf092 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.3 2002/04/27 03:45:01 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.4 2002/05/17 18:32:52 petere Exp $
  *
  * DESCRIPTION
  *   These routines take the parse tree and pick out the
@@ -159,6 +159,104 @@ compute_parameter_types(List *argTypes, Oid languageOid,
    return parameterCount;
 }
 
+
+/*
+ * Dissect the list of options assembled in gram.y into function
+ * attributes.
+ */
+
+static void
+compute_attributes_sql_style(const List *options,
+                            List **as,
+                            char **language,
+                            char *volatility_p,
+                            bool *strict_p,
+                            bool *security_definer,
+                            bool *implicit_cast)
+{
+   const List *option;
+   DefElem *as_item = NULL;
+   DefElem *language_item = NULL;
+   DefElem *volatility_item = NULL;
+   DefElem *strict_item = NULL;
+   DefElem *security_item = NULL;
+   DefElem *implicit_item = NULL;
+
+   foreach(option, options)
+   {
+       DefElem    *defel = (DefElem *) lfirst(option);
+
+       if (strcmp(defel->defname, "as")==0)
+       {
+           if (as_item)
+               elog(ERROR, "conflicting or redundant options");
+           as_item = defel;
+       }
+       else if (strcmp(defel->defname, "language")==0)
+       {
+           if (language_item)
+               elog(ERROR, "conflicting or redundant options");
+           language_item = defel;
+       }
+       else if (strcmp(defel->defname, "volatility")==0)
+       {
+           if (volatility_item)
+               elog(ERROR, "conflicting or redundant options");
+           volatility_item = defel;
+       }
+       else if (strcmp(defel->defname, "strict")==0)
+       {
+           if (strict_item)
+               elog(ERROR, "conflicting or redundant options");
+           strict_item = defel;
+       }
+       else if (strcmp(defel->defname, "security")==0)
+       {
+           if (security_item)
+               elog(ERROR, "conflicting or redundant options");
+           security_item = defel;
+       }
+       else if (strcmp(defel->defname, "implicit")==0)
+       {
+           if (implicit_item)
+               elog(ERROR, "conflicting or redundant options");
+           implicit_item = defel;
+       }
+       else
+           elog(ERROR, "invalid CREATE FUNCTION option");
+   }
+
+   if (as_item)
+       *as = (List *)as_item->arg;
+   else
+       elog(ERROR, "no function body specified");
+
+   if (language_item)
+       *language = strVal(language_item->arg);
+   else
+       elog(ERROR, "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");
+   }
+
+   if (strict_item)
+       *strict_p = intVal(strict_item->arg);
+   if (security_item)
+       *security_definer = intVal(security_item->arg);
+   if (implicit_item)
+       *implicit_cast = intVal(implicit_item->arg);
+}
+
+
 /*-------------
  *  Interpret the parameters *parameters and return their contents as
  *  *byte_pct_p, etc.
@@ -183,23 +281,14 @@ compute_parameter_types(List *argTypes, Oid languageOid,
  *------------
  */
 static void
-compute_full_attributes(List *parameters,
-                       int32 *byte_pct_p, int32 *perbyte_cpu_p,
-                       int32 *percall_cpu_p, int32 *outin_ratio_p,
-                       bool *isImplicit_p, bool *isStrict_p,
-                       char *volatility_p)
+compute_attributes_with_style(List *parameters,
+                             int32 *byte_pct_p, int32 *perbyte_cpu_p,
+                             int32 *percall_cpu_p, int32 *outin_ratio_p,
+                             bool *isImplicit_p, bool *isStrict_p,
+                             char *volatility_p)
 {
    List       *pl;
 
-   /* the defaults */
-   *byte_pct_p = BYTE_PCT;
-   *perbyte_cpu_p = PERBYTE_CPU;
-   *percall_cpu_p = PERCALL_CPU;
-   *outin_ratio_p = OUTIN_RATIO;
-   *isImplicit_p = false;
-   *isStrict_p = false;
-   *volatility_p = PROVOLATILE_VOLATILE;
-
    foreach(pl, parameters)
    {
        DefElem    *param = (DefElem *) lfirst(pl);
@@ -290,12 +379,13 @@ interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
  *  Execute a CREATE FUNCTION utility statement.
  */
 void
-CreateFunction(ProcedureStmt *stmt)
+CreateFunction(CreateFunctionStmt *stmt)
 {
    char       *probin_str;
    char       *prosrc_str;
    Oid         prorettype;
    bool        returnsSet;
+   char       *language;
    char        languageName[NAMEDATALEN];
    Oid         languageOid;
    char       *funcname;
@@ -308,10 +398,12 @@ CreateFunction(ProcedureStmt *stmt)
                percall_cpu,
                outin_ratio;
    bool        isImplicit,
-               isStrict;
+               isStrict,
+               security;
    char        volatility;
    HeapTuple   languageTuple;
    Form_pg_language languageStruct;
+   List       *as_clause;
 
    /* Convert list of names to a name and namespace */
    namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@@ -322,8 +414,21 @@ CreateFunction(ProcedureStmt *stmt)
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, get_namespace_name(namespaceId));
 
+   /* defaults attributes */
+   byte_pct = BYTE_PCT;
+   perbyte_cpu = PERBYTE_CPU;
+   percall_cpu = PERCALL_CPU;
+   outin_ratio = OUTIN_RATIO;
+   isImplicit = false;
+   isStrict = false;
+   volatility = PROVOLATILE_VOLATILE;
+
+   /* override attributes from explicit list */
+   compute_attributes_sql_style(stmt->options,
+                                &as_clause, &language, &volatility, &isStrict, &security, &isImplicit);
+
    /* Convert language name to canonical case */
-   case_translate_language_name(stmt->language, languageName);
+   case_translate_language_name(language, languageName);
 
    /* Look up the language and validate permissions */
    languageTuple = SearchSysCache(LANGNAME,
@@ -363,12 +468,12 @@ CreateFunction(ProcedureStmt *stmt)
    parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
                                             parameterTypes);
 
-   compute_full_attributes(stmt->withClause,
-                           &byte_pct, &perbyte_cpu, &percall_cpu,
-                           &outin_ratio, &isImplicit, &isStrict,
-                           &volatility);
+   compute_attributes_with_style(stmt->withClause,
+                                 &byte_pct, &perbyte_cpu, &percall_cpu,
+                                 &outin_ratio, &isImplicit, &isStrict,
+                                 &volatility);
 
-   interpret_AS_clause(languageOid, languageName, stmt->as,
+   interpret_AS_clause(languageOid, languageName, as_clause,
                        &prosrc_str, &probin_str);
 
    /*
index 909847dc856cc6d030a86b90ff1c96bdbdd22300..1f0cc11934ffa6d00abf51f0147e811cbe00d31c 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.186 2002/05/17 01:19:17 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.187 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2098,18 +2098,17 @@ _copyIndexStmt(IndexStmt *from)
    return newnode;
 }
 
-static ProcedureStmt *
-_copyProcedureStmt(ProcedureStmt *from)
+static CreateFunctionStmt *
+_copyCreateFunctionStmt(CreateFunctionStmt *from)
 {
-   ProcedureStmt *newnode = makeNode(ProcedureStmt);
+   CreateFunctionStmt *newnode = makeNode(CreateFunctionStmt);
 
    newnode->replace = from->replace;
    Node_Copy(from, newnode, funcname);
    Node_Copy(from, newnode, argTypes);
    Node_Copy(from, newnode, returnType);
+   Node_Copy(from, newnode, options);
    Node_Copy(from, newnode, withClause);
-   Node_Copy(from, newnode, as);
-   newnode->language = pstrdup(from->language);
 
    return newnode;
 }
@@ -2865,8 +2864,8 @@ copyObject(void *from)
        case T_IndexStmt:
            retval = _copyIndexStmt(from);
            break;
-       case T_ProcedureStmt:
-           retval = _copyProcedureStmt(from);
+       case T_CreateFunctionStmt:
+           retval = _copyCreateFunctionStmt(from);
            break;
        case T_RemoveAggrStmt:
            retval = _copyRemoveAggrStmt(from);
index 1f0d175326b2ba39e80f246d74dec2d60feeee8f..f48d6d033f49a872d861829b346996c507d6e685 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.133 2002/05/17 01:19:17 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.134 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -923,7 +923,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
 }
 
 static bool
-_equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
+_equalCreateFunctionStmt(CreateFunctionStmt *a, CreateFunctionStmt *b)
 {
    if (a->replace != b->replace)
        return false;
@@ -933,11 +933,9 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
        return false;
    if (!equal(a->returnType, b->returnType))
        return false;
-   if (!equal(a->withClause, b->withClause))
-       return false;
-   if (!equal(a->as, b->as))
+   if (!equal(a->options, b->options))
        return false;
-   if (!equalstr(a->language, b->language))
+   if (!equal(a->withClause, b->withClause))
        return false;
 
    return true;
@@ -2020,8 +2018,8 @@ equal(void *a, void *b)
        case T_IndexStmt:
            retval = _equalIndexStmt(a, b);
            break;
-       case T_ProcedureStmt:
-           retval = _equalProcedureStmt(a, b);
+       case T_CreateFunctionStmt:
+           retval = _equalCreateFunctionStmt(a, b);
            break;
        case T_RemoveAggrStmt:
            retval = _equalRemoveAggrStmt(a, b);
index 0009b9df2f03b432ff09bdec7076420b23d61af9..70a9e78cfa07df4dfd2963edaf85d01703669e54 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.316 2002/05/17 01:19:17 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.317 2002/05/17 18:32:52 petere Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -141,7 +141,7 @@ static void doNegateFloat(Value *v);
        DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropAssertStmt, DropTrigStmt,
        DropRuleStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
        GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
-       NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
+       NotifyStmt, OptimizableStmt, CreateFunctionStmt, ReindexStmt,
        RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
        RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
        RuleStmt, SelectStmt, TransactionStmt, TruncateStmt,
@@ -201,7 +201,7 @@ static void doNegateFloat(Value *v);
 
 %type    stmtblock, stmtmulti,
        OptTableElementList, OptInherit, definition, opt_distinct,
-       opt_with, func_args, func_args_list, func_as,
+       opt_with, func_args, func_args_list, func_as, createfunc_opt_list
        oper_argtypes, RuleActionList, RuleActionMulti,
        opt_column_list, columnList, opt_name_list,
        sort_clause, sortby_list, index_params, index_list, name_list,
@@ -214,6 +214,7 @@ static void doNegateFloat(Value *v);
 
 %type   into_clause, OptTempTableName
 
+%type   createfunc_opt_item
 %type  func_arg, func_return, func_type, aggr_argtype
 
 %type     opt_arg, TriggerForOpt, TriggerForType, OptTemp, OptWithOids
@@ -388,6 +389,9 @@ static void doNegateFloat(Value *v);
        TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED, 
        UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
 
+%token  CALLED, DEFINER, EXTERNAL, IMMUTABLE, IMPLICIT, INPUT,
+       INVOKER, SECURITY, STABLE, STRICT, VOLATILE
+
 /* The grammar thinks these are keywords, but they are not in the keywords.c
  * list and so can never be entered directly.  The filter in parser.c
  * creates these tokens when required.
@@ -467,6 +471,7 @@ stmt : AlterDatabaseSetStmt
        | CreateStmt
        | CreateAsStmt
        | CreateDomainStmt
+       | CreateFunctionStmt
        | CreateSchemaStmt
        | CreateGroupStmt
        | CreateSeqStmt
@@ -494,7 +499,6 @@ stmt : AlterDatabaseSetStmt
        | UnlistenStmt
        | LockStmt
        | NotifyStmt
-       | ProcedureStmt
        | ReindexStmt
        | RemoveAggrStmt
        | RemoveOperStmt
@@ -2769,17 +2773,16 @@ RecipeStmt:  EXECUTE RECIPE recipe_name
  *
  *****************************************************************************/
 
-ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args
-            RETURNS func_return AS func_as LANGUAGE ColId_or_Sconst opt_with
+CreateFunctionStmt:    CREATE opt_or_replace FUNCTION func_name func_args
+            RETURNS func_return createfunc_opt_list opt_with
                {
-                   ProcedureStmt *n = makeNode(ProcedureStmt);
+                   CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
                    n->replace = $2;
                    n->funcname = $4;
                    n->argTypes = $5;
                    n->returnType = $7;
-                   n->withClause = $12;
-                   n->as = $9;
-                   n->language = $11;
+                   n->options = $8;
+                   n->withClause = $9;
                    $$ = (Node *)n;
                };
 
@@ -2787,10 +2790,6 @@ opt_or_replace:  OR REPLACE                      { $$ = TRUE; }
        | /*EMPTY*/                             { $$ = FALSE; }
        ;
 
-opt_with:  WITH definition                     { $$ = $2; }
-       | /*EMPTY*/                             { $$ = NIL; }
-       ;
-
 func_args:  '(' func_args_list ')'             { $$ = $2; }
        | '(' ')'                               { $$ = NIL; }
        ;
@@ -2831,12 +2830,6 @@ opt_arg:  IN
                }
        ;
 
-func_as: Sconst
-               {   $$ = makeList1(makeString($1)); }
-       | Sconst ',' Sconst
-               {   $$ = makeList2(makeString($1), makeString($3)); }
-       ;
-
 func_return:  func_type
                {
                    /* We can catch over-specified arguments here if we want to,
@@ -2864,6 +2857,104 @@ func_type:  Typename
                }
        ;
 
+
+createfunc_opt_list: createfunc_opt_item
+                { $$ = makeList1($1); }
+        | createfunc_opt_list createfunc_opt_item
+                { $$ = lappend($1, $2); }
+        ;
+
+createfunc_opt_item: AS func_as
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "as";
+                   $$->arg = (Node *)$2;
+               }
+       | LANGUAGE ColId_or_Sconst
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "language";
+                   $$->arg = (Node *)makeString($2);
+               }
+       | IMMUTABLE
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "volatility";
+                   $$->arg = (Node *)makeString("immutable");
+               }
+       | STABLE
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "volatility";
+                   $$->arg = (Node *)makeString("stable");
+               }
+       | VOLATILE
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "volatility";
+                   $$->arg = (Node *)makeString("volatile");
+               }
+       | CALLED ON NULL_P INPUT
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "strict";
+                   $$->arg = (Node *)makeInteger(FALSE);
+               }
+       | RETURNS NULL_P ON NULL_P INPUT
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "strict";
+                   $$->arg = (Node *)makeInteger(TRUE);
+               }
+       | STRICT
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "strict";
+                   $$->arg = (Node *)makeInteger(TRUE);
+               }
+       | EXTERNAL SECURITY DEFINER
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "security";
+                   $$->arg = (Node *)makeInteger(TRUE);
+               }
+       | EXTERNAL SECURITY INVOKER
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "security";
+                   $$->arg = (Node *)makeInteger(FALSE);
+               }
+       | SECURITY DEFINER
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "security";
+                   $$->arg = (Node *)makeInteger(TRUE);
+               }
+       | SECURITY INVOKER
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "security";
+                   $$->arg = (Node *)makeInteger(FALSE);
+               }
+       | IMPLICIT CAST
+               {
+                   $$ = makeNode(DefElem);
+                   $$->defname = "implicit";
+                   $$->arg = (Node *)makeInteger(TRUE);
+               }
+       ;
+
+func_as: Sconst
+               {   $$ = makeList1(makeString($1)); }
+       | Sconst ',' Sconst
+               {   $$ = makeList2(makeString($1), makeString($3)); }
+       ;
+
+opt_with:  WITH definition                     { $$ = $2; }
+       | /*EMPTY*/                             { $$ = NIL; }
+       ;
+
+
 /*****************************************************************************
  *
  *     QUERY:
@@ -6137,6 +6228,7 @@ unreserved_keyword:
        | BEGIN_TRANS
        | BY
        | CACHE
+       | CALLED
        | CASCADE
        | CHAIN
        | CHARACTERISTICS
@@ -6156,6 +6248,7 @@ unreserved_keyword:
        | DAY_P
        | DECLARE
        | DEFERRED
+       | DEFINER
        | DELETE
        | DELIMITERS
        | DOMAIN_P
@@ -6168,6 +6261,7 @@ unreserved_keyword:
        | EXCLUSIVE
        | EXECUTE
        | EXPLAIN
+       | EXTERNAL
        | FETCH
        | FORCE
        | FORWARD
@@ -6176,13 +6270,17 @@ unreserved_keyword:
        | HANDLER
        | HOUR_P
        | IMMEDIATE
+       | IMMUTABLE
+       | IMPLICIT
        | INCREMENT
        | INDEX
        | INHERITS
        | INOUT
+       | INPUT
        | INSENSITIVE
        | INSERT
        | INSTEAD
+       | INVOKER
        | ISOLATION
        | KEY
        | LANGUAGE
@@ -6238,18 +6336,21 @@ unreserved_keyword:
        | SCHEMA
        | SCROLL
        | SECOND_P
+       | SECURITY
        | SESSION
        | SEQUENCE
        | SERIALIZABLE
        | SET
        | SHARE
        | SHOW
+       | STABLE
        | START
        | STATEMENT
        | STATISTICS
        | STDIN
        | STDOUT
        | STORAGE
+       | STRICT
        | SYSID
        | TEMP
        | TEMPLATE
@@ -6272,6 +6373,7 @@ unreserved_keyword:
        | VARYING
        | VERSION
        | VIEW
+       | VOLATILE
        | WITH
        | WITHOUT
        | WORK
index 0c7612350a50072ba2a695f2ab3e6f67fdfb1ceb..36900127ea8c7ed80b96c1dc9d699615b5d35f41 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.109 2002/05/03 00:32:16 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.110 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"both", BOTH},
    {"by", BY},
    {"cache", CACHE},
+   {"called", CALLED},
    {"cascade", CASCADE},
    {"case", CASE},
    {"cast", CAST},
@@ -95,6 +96,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"default", DEFAULT},
    {"deferrable", DEFERRABLE},
    {"deferred", DEFERRED},
+   {"definer", DEFINER},
    {"delete", DELETE},
    {"delimiters", DELIMITERS},
    {"desc", DESC},
@@ -114,6 +116,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"execute", EXECUTE},
    {"exists", EXISTS},
    {"explain", EXPLAIN},
+   {"external", EXTERNAL},
    {"extract", EXTRACT},
    {"false", FALSE_P},
    {"fetch", FETCH},
@@ -134,6 +137,8 @@ static const ScanKeyword ScanKeywords[] = {
    {"hour", HOUR_P},
    {"ilike", ILIKE},
    {"immediate", IMMEDIATE},
+   {"immutable", IMMUTABLE},
+   {"implicit", IMPLICIT},
    {"in", IN},
    {"increment", INCREMENT},
    {"index", INDEX},
@@ -141,6 +146,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"initially", INITIALLY},
    {"inner", INNER_P},
    {"inout", INOUT},
+   {"input", INPUT},
    {"insensitive", INSENSITIVE},
    {"insert", INSERT},
    {"instead", INSTEAD},
@@ -149,6 +155,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"intersect", INTERSECT},
    {"interval", INTERVAL},
    {"into", INTO},
+   {"invoker", INVOKER},
    {"is", IS},
    {"isnull", ISNULL},
    {"isolation", ISOLATION},
@@ -234,6 +241,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"schema", SCHEMA},
    {"scroll", SCROLL},
    {"second", SECOND_P},
+   {"security", SECURITY},
    {"select", SELECT},
    {"sequence", SEQUENCE},
    {"serializable", SERIALIZABLE},
@@ -245,12 +253,14 @@ static const ScanKeyword ScanKeywords[] = {
    {"show", SHOW},
    {"smallint", SMALLINT},
    {"some", SOME},
+   {"stable", STABLE},
    {"start", START},
    {"statement", STATEMENT},
    {"statistics", STATISTICS},
    {"stdin", STDIN},
    {"stdout", STDOUT},
    {"storage", STORAGE},
+   {"strict", STRICT},
    {"substring", SUBSTRING},
    {"sysid", SYSID},
    {"table", TABLE},
@@ -288,6 +298,7 @@ static const ScanKeyword ScanKeywords[] = {
    {"verbose", VERBOSE},
    {"version", VERSION},
    {"view", VIEW},
+   {"volatile", VOLATILE},
    {"when", WHEN},
    {"where", WHERE},
    {"with", WITH},
index 53bf45dce9c796870a916bcb78c80236b18d7043..1ea4fa9a6b546b4ee592c3f17f54b746f720236f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.265 2002/05/17 01:19:18 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.266 2002/05/17 18:32:52 petere Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -1688,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username)
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.265 $ $Date: 2002/05/17 01:19:18 $\n");
+       puts("$Revision: 1.266 $ $Date: 2002/05/17 18:32:52 $\n");
    }
 
    /*
@@ -2229,7 +2229,7 @@ CreateCommandTag(Node *parsetree)
            tag = "CREATE";
            break;
 
-       case T_ProcedureStmt:   /* CREATE FUNCTION */
+       case T_CreateFunctionStmt:  /* CREATE FUNCTION */
            tag = "CREATE";
            break;
 
index e72d8dfccf7c3d62870e10af2fff7e29401c6946..e7091d9aa34a7b442b740bf8f2d10bfc71b17e36 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.154 2002/05/17 01:19:18 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.155 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -574,8 +574,8 @@ ProcessUtility(Node *parsetree,
            }
            break;
 
-       case T_ProcedureStmt:   /* CREATE FUNCTION */
-           CreateFunction((ProcedureStmt *) parsetree);
+       case T_CreateFunctionStmt:  /* CREATE FUNCTION */
+           CreateFunction((CreateFunctionStmt *) parsetree);
            break;
 
        case T_IndexStmt:       /* CREATE INDEX */
index f3b8f8a19b1b418d8164f12272d8f9c1d15f1aac..cb268c50bf1cf2356c5546aa54c99817ddc3e9ff 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.260 2002/05/13 17:45:30 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.261 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3152,18 +3152,14 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs)
 
        (*deps)[depIdx++] = strdup(lanplcallfoid);
 
-       appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
-       formatStringLiteral(delqry, lanname, CONV_ALL);
-       appendPQExpBuffer(delqry, ";\n");
+       appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n", fmtId(lanname, force_quotes));
 
-       appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
+       appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
                          (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
-                         "TRUSTED " : "");
-       formatStringLiteral(defqry, lanname, CONV_ALL);
-       appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
+                         "TRUSTED " : "",
+                         fmtId(lanname, force_quotes));
+       appendPQExpBuffer(defqry, " HANDLER %s;\n",
                          fmtId(finfo[fidx].proname, force_quotes));
-       formatStringLiteral(defqry, lancompiler, CONV_ALL);
-       appendPQExpBuffer(defqry, ";\n");
 
        (*deps)[depIdx++] = NULL;       /* End of List */
 
@@ -3221,9 +3217,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
    char       *proimplicit;
    char       *proisstrict;
    char       *lanname;
-   char       *listSep;
-   char       *listSepComma = ",";
-   char       *listSepNone = "";
    char       *rettypename;
 
    if (finfo->dumped)
@@ -3337,52 +3330,33 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
    rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
 
    appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
-   appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
+   appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE %s",
                      (proretset[0] == 't') ? "SETOF " : "",
                      rettypename,
-                     asPart->data);
-   formatStringLiteral(q, lanname, CONV_ALL);
+                     asPart->data,
+                     fmtId(lanname, force_quotes));
 
    free(rettypename);
 
-   if (provolatile[0] != PROVOLATILE_VOLATILE ||
-       proimplicit[0] == 't' ||
-       proisstrict[0] == 't')  /* OR in new attrs here */
+   if (provolatile[0] != PROVOLATILE_VOLATILE)
    {
-       appendPQExpBuffer(q, " WITH (");
-       listSep = listSepNone;
-
        if (provolatile[0] == PROVOLATILE_IMMUTABLE)
-       {
-           appendPQExpBuffer(q, "%s isImmutable", listSep);
-           listSep = listSepComma;
-       }
+           appendPQExpBuffer(q, " IMMUTABLE");
        else if (provolatile[0] == PROVOLATILE_STABLE)
-       {
-           appendPQExpBuffer(q, "%s isStable", listSep);
-           listSep = listSepComma;
-       }
+           appendPQExpBuffer(q, " STABLE");
        else if (provolatile[0] != PROVOLATILE_VOLATILE)
        {
            write_msg(NULL, "Unexpected provolatile value for function %s\n",
                      finfo->proname);
            exit_nicely();
        }
+   }   
 
-       if (proimplicit[0] == 't')
-       {
-           appendPQExpBuffer(q, "%s implicitCoercion", listSep);
-           listSep = listSepComma;
-       }
+   if (proimplicit[0] == 't')
+       appendPQExpBuffer(q, " IMPLICIT CAST");
 
-       if (proisstrict[0] == 't')
-       {
-           appendPQExpBuffer(q, "%s isStrict", listSep);
-           listSep = listSepComma;
-       }
-
-       appendPQExpBuffer(q, " )");
-   }
+   if (proisstrict[0] == 't')
+       appendPQExpBuffer(q, " STRICT");
 
    appendPQExpBuffer(q, ";\n");
 
index 4e257fbd91a42eb170c2c5895b9b8c7f11c8fad6..cf9048c714be3e01ba235eeac58c517b063651ec 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.36 2002/04/16 23:08:12 tgl Exp $
+ * $Id: defrem.h,v 1.37 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,7 +38,7 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all);
  * DefineFoo and RemoveFoo are now both in foocmds.c
  */
 
-extern void CreateFunction(ProcedureStmt *stmt);
+extern void CreateFunction(CreateFunctionStmt *stmt);
 extern void RemoveFunction(List *functionName, List *argTypes);
 
 extern void DefineOperator(List *names, List *parameters);
index 7de647d1362bcf2bb0dddc55c28ad4dfbdd4b72c..6aa253e9d41b886d20e0be7ecbbdafbc027b0c21 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.107 2002/05/12 23:43:04 tgl Exp $
+ * $Id: nodes.h,v 1.108 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -160,7 +160,7 @@ typedef enum NodeTag
    T_CommentStmt,
    T_FetchStmt,
    T_IndexStmt,
-   T_ProcedureStmt,
+   T_CreateFunctionStmt,
    T_RemoveAggrStmt,
    T_RemoveFuncStmt,
    T_RemoveOperStmt,
index a0bf47d7ed061a2ada424897f9b9a5b6235cf60d..3466e12598245b1766e7eb4f726800d7a4ae16c4 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.177 2002/05/17 01:19:19 tgl Exp $
+ * $Id: parsenodes.h,v 1.178 2002/05/17 18:32:52 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1200,17 +1200,16 @@ typedef struct IndexStmt
  *     Create Function Statement
  * ----------------------
  */
-typedef struct ProcedureStmt
+typedef struct CreateFunctionStmt
 {
    NodeTag     type;
    bool        replace;        /* T => replace if already exists */
    List       *funcname;       /* qualified name of function to create */
    List       *argTypes;       /* list of argument types (TypeName nodes) */
    TypeName   *returnType;     /* the return type */
+   List       *options;        /* a list of DefElem */
    List       *withClause;     /* a list of DefElem */
-   List       *as;             /* definition of function body */
-   char       *language;       /* C, SQL, etc */
-} ProcedureStmt;
+} CreateFunctionStmt;
 
 /* ----------------------
  *     Drop Aggregate Statement