diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 69bfe4c1578d92d6639ad3384c18b65dfc9f743a..fc5ed839376018f1cba6d698727f626e226c615f 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -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)
 	{
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index a8c9f1199e44fc19ac4df32663d9735eb600d108..5bbb4bfdf745fa430d6161cc2caf9086e5bb50a1 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -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