*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Oid finalfn = InvalidOid; /* can be omitted */
Oid sortop = InvalidOid; /* can be omitted */
bool hasPolyArg;
+ bool hasInternalArg;
Oid rettype;
Oid finaltype;
Oid *fnArgs;
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;
}
/*
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)
{
*
*
* 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
*
* 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