]> granicus.if.org Git - postgresql/commitdiff
In CREATE AGGREGATE, allow the transition datatype to be "internal", but only
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Nov 2008 19:47:50 +0000 (19:47 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Nov 2008 19:47:50 +0000 (19:47 +0000)
if the user is superuser.  This makes available to extension modules the same
sort of trick being practiced by array_agg().  The reason for the superuser
restriction is that you could crash the system by connecting up an
incompatible pair of internal-using functions as an aggregate.  It shouldn't
interfere with any legitimate use, since you'd have to be superuser to create
the internal-using transition and final functions anyway.

src/backend/catalog/pg_aggregate.c
src/backend/commands/aggregatecmds.c

index 69bfe4c1578d92d6639ad3384c18b65dfc9f743a..fc5ed839376018f1cba6d698727f626e226c615f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.96 2008/11/02 01:45:27 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.97 2008/11/14 19:47:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,7 @@ AggregateCreate(const char *aggName,
        Oid                     finalfn = InvalidOid;   /* can be omitted */
        Oid                     sortop = InvalidOid;    /* can be omitted */
        bool            hasPolyArg;
+       bool            hasInternalArg;
        Oid                     rettype;
        Oid                     finaltype;
        Oid                *fnArgs;
@@ -78,15 +79,15 @@ AggregateCreate(const char *aggName,
        if (!aggtransfnName)
                elog(ERROR, "aggregate must have a transition function");
 
-       /* check for polymorphic arguments */
+       /* check for polymorphic and INTERNAL arguments */
        hasPolyArg = false;
+       hasInternalArg = false;
        for (i = 0; i < numArgs; i++)
        {
                if (IsPolymorphicType(aggArgTypes[i]))
-               {
                        hasPolyArg = true;
-                       break;
-               }
+               else if (aggArgTypes[i] == INTERNALOID)
+                       hasInternalArg = true;
        }
 
        /*
@@ -177,6 +178,18 @@ AggregateCreate(const char *aggName,
                                 errdetail("An aggregate returning a polymorphic type "
                                                   "must have at least one polymorphic argument.")));
 
+       /*
+        * Also, the return type can't be INTERNAL unless there's at least one
+        * INTERNAL argument.  This is the same type-safety restriction we
+        * enforce for regular functions, but at the level of aggregates.  We
+        * must test this explicitly because we allow INTERNAL as the transtype.
+        */
+       if (finaltype == INTERNALOID && !hasInternalArg)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+                                errmsg("unsafe use of pseudo-type \"internal\""),
+                                errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
+
        /* handle sortop, if supplied */
        if (aggsortopName)
        {
index a8c9f1199e44fc19ac4df32663d9735eb600d108..5bbb4bfdf745fa430d6161cc2caf9086e5bb50a1 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.46 2008/06/08 21:09:48 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.47 2008/11/14 19:47:50 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -173,15 +173,24 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
         *
         * transtype can't be a pseudo-type, since we need to be able to store
         * values of the transtype.  However, we can allow polymorphic transtype
-        * in some cases (AggregateCreate will check).
+        * in some cases (AggregateCreate will check).  Also, we allow "internal"
+        * for functions that want to pass pointers to private data structures;
+        * but allow that only to superusers, since you could crash the system
+        * (or worse) by connecting up incompatible internal-using functions
+        * in an aggregate.
         */
        transTypeId = typenameTypeId(NULL, transType, NULL);
        if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
                !IsPolymorphicType(transTypeId))
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-                                errmsg("aggregate transition data type cannot be %s",
-                                               format_type_be(transTypeId))));
+       {
+               if (transTypeId == INTERNALOID && superuser())
+                       /* okay */ ;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+                                        errmsg("aggregate transition data type cannot be %s",
+                                                       format_type_be(transTypeId))));
+       }
 
        /*
         * Most of the argument-checking is done inside of AggregateCreate