diff options
author | Tom Lane | 2008-11-14 19:47:50 +0000 |
---|---|---|
committer | Tom Lane | 2008-11-14 19:47:50 +0000 |
commit | 04ceebf6ed24981818af13bc9a447b8acf0c1b53 (patch) | |
tree | 7d32f32535f0141016ce5683ac74d17e4d68944e | |
parent | 7cc080cc94eecaeea3077b9e94bb8015df9c2826 (diff) |
In CREATE AGGREGATE, allow the transition datatype to be "internal", but only
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.
-rw-r--r-- | src/backend/catalog/pg_aggregate.c | 21 | ||||
-rw-r--r-- | src/backend/commands/aggregatecmds.c | 19 |
2 files changed, 31 insertions, 9 deletions
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 7399123942..8ec82fd11b 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -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) { diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index b61187a826..2d7b248bd2 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -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 |