diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml index 3df3303..c630850 100644 --- a/doc/src/sgml/ref/create_aggregate.sgml +++ b/doc/src/sgml/ref/create_aggregate.sgml @@ -472,9 +472,15 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1; Deserializes a previously serialized aggregate state back into state_data_type. This - function must take a single argument of - serialtype and return - state_data_type. + function must take a two arguments, the first of which should be of type + serialtype and the second + must be of type INTERNAL. The return type must be + state_data_type. The second + argument serves no purpose other than to allow users to define their own + deserialfunc as the + creation of functions which return INTERNAL and contain no + INTERNAL arguments is disallowed by + PostgreSQL. diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 73d19ec..6e17e90 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -462,13 +462,17 @@ AggregateCreate(const char *aggName, /* * Validate the deserialization function, if present. We must ensure that - * the return type of this function is the same as the transType. + * the return type of this function is the same as the transType. The 2nd + * argument of the deserialization function is a dummy and only exists as + * CREATE FUNCTION is disallowed for functions returning INTERNAL which + * don't have any INTERNAL arguments. */ if (aggdeserialfnName) { fnArgs[0] = aggSerialType; + fnArgs[1] = INTERNALOID; /* dummy */ - deserialfn = lookup_agg_function(aggdeserialfnName, 1, + deserialfn = lookup_agg_function(aggdeserialfnName, 2, fnArgs, variadicArgType, &rettype); diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 7b282de..5dee66f 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -998,6 +998,16 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup) dsinfo->argnull[0] = slot->tts_isnull[0]; /* + * The 2nd argument of the deserial function is merely a dummy + * which serves only to allow users to create their own + * deserial functions. CREATE FUNCTION disallows the creation + * of functions returning an INTERNAL if the function does not + * have any INTERNAL typed arguments. + */ + dsinfo->arg[1] = (Datum) 0; + dsinfo->argnull[1] = true; + + /* * We run the deserialization functions in per-input-tuple * memory context. */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 6a65e77..ad84135 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2451,11 +2451,11 @@ DATA(insert OID = 3337 ( numeric_avg_combine PGNSP PGUID 12 1 0 0 0 f f f f f DESCR("aggregate combine function"); DATA(insert OID = 2740 ( numeric_avg_serialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2281" _null_ _null_ _null_ _null_ _null_ numeric_avg_serialize _null_ _null_ _null_ )); DESCR("aggregate serial function"); -DATA(insert OID = 2741 ( numeric_avg_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2281 "17" _null_ _null_ _null_ _null_ _null_ numeric_avg_deserialize _null_ _null_ _null_ )); +DATA(insert OID = 2741 ( numeric_avg_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_avg_deserialize _null_ _null_ _null_ )); DESCR("aggregate deserial function"); DATA(insert OID = 3335 ( numeric_serialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2281" _null_ _null_ _null_ _null_ _null_ numeric_serialize _null_ _null_ _null_ )); DESCR("aggregate serial function"); -DATA(insert OID = 3336 ( numeric_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2281 "17" _null_ _null_ _null_ _null_ _null_ numeric_deserialize _null_ _null_ _null_ )); +DATA(insert OID = 3336 ( numeric_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_deserialize _null_ _null_ _null_ )); DESCR("aggregate deserial function"); DATA(insert OID = 3548 ( numeric_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i s 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ _null_ numeric_accum_inv _null_ _null_ _null_ )); DESCR("aggregate transition function"); @@ -2469,7 +2469,7 @@ DATA(insert OID = 3338 ( numeric_poly_combine PGNSP PGUID 12 1 0 0 0 f f f f DESCR("aggregate combine function"); DATA(insert OID = 3339 ( numeric_poly_serialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2281" _null_ _null_ _null_ _null_ _null_ numeric_poly_serialize _null_ _null_ _null_ )); DESCR("aggregate serial function"); -DATA(insert OID = 3340 ( numeric_poly_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2281 "17" _null_ _null_ _null_ _null_ _null_ numeric_poly_deserialize _null_ _null_ _null_ )); +DATA(insert OID = 3340 ( numeric_poly_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_poly_deserialize _null_ _null_ _null_ )); DESCR("aggregate deserial function"); DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i s 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); @@ -2485,7 +2485,7 @@ DATA(insert OID = 2785 ( int8_avg_combine PGNSP PGUID 12 1 0 0 0 f f f f f f DESCR("aggregate combine function"); DATA(insert OID = 2786 ( int8_avg_serialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2281" _null_ _null_ _null_ _null_ _null_ int8_avg_serialize _null_ _null_ _null_ )); DESCR("aggregate serial function"); -DATA(insert OID = 2787 ( int8_avg_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2281 "17" _null_ _null_ _null_ _null_ _null_ int8_avg_deserialize _null_ _null_ _null_ )); +DATA(insert OID = 2787 ( int8_avg_deserialize PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ int8_avg_deserialize _null_ _null_ _null_ )); DESCR("aggregate deserial function"); DATA(insert OID = 3324 ( int4_avg_combine PGNSP PGUID 12 1 0 0 0 f f f f f f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ int4_avg_combine _null_ _null_ _null_ )); DESCR("aggregate combine function"); diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out index 625dae5..642e365 100644 --- a/src/test/regress/expected/create_aggregate.out +++ b/src/test/regress/expected/create_aggregate.out @@ -145,7 +145,7 @@ CREATE AGGREGATE myavg (numeric) serialfunc = numeric_avg_serialize, deserialfunc = numeric_avg_serialize ); -ERROR: function numeric_avg_serialize(bytea) does not exist +ERROR: function numeric_avg_serialize(bytea, internal) does not exist -- ensure return type of serialfunc is checked CREATE AGGREGATE myavg (numeric) ( diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index b159640..cfbe10c 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -279,21 +279,15 @@ ORDER BY 1, 2; -- Look for functions that return type "internal" and do not have any -- "internal" argument. Such a function would be a security hole since -- it might be used to call an internal function from an SQL command. --- As of 7.3 this query should find internal_in, and as of 9.6 aggregate --- deserialization will be found too. These should contain a runtime check to --- ensure they can only be called in an aggregate context. +-- As of 7.3 this query should find only internal_in. SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prorettype = 'internal'::regtype AND NOT 'internal'::regtype = ANY (p1.proargtypes); - oid | proname -------+-------------------------- - 2741 | numeric_avg_deserialize - 3336 | numeric_deserialize - 3340 | numeric_poly_deserialize - 2787 | int8_avg_deserialize + oid | proname +------+------------- 2304 | internal_in -(5 rows) +(1 row) -- Look for functions that return a polymorphic type and do not have any -- polymorphic argument. Calls of such functions would be unresolvable diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 62c84d0..fb70d26 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -228,9 +228,7 @@ ORDER BY 1, 2; -- Look for functions that return type "internal" and do not have any -- "internal" argument. Such a function would be a security hole since -- it might be used to call an internal function from an SQL command. --- As of 7.3 this query should find internal_in, and as of 9.6 aggregate --- deserialization will be found too. These should contain a runtime check to --- ensure they can only be called in an aggregate context. +-- As of 7.3 this query should find only internal_in. SELECT p1.oid, p1.proname FROM pg_proc as p1