1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_aggregate relation
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_aggregate.c
13 *-------------------------------------------------------------------------
17 #include "access/htup_details.h"
18 #include "access/table.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_aggregate.h"
22 #include "catalog/pg_language.h"
23 #include "catalog/pg_operator.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "parser/parse_coerce.h"
28 #include "parser/parse_func.h"
29 #include "parser/parse_oper.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
37 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
46 AggregateCreate(const char *aggName,
51 oidvector *parameterTypes,
52 Datum allParameterTypes,
55 List *parameterDefaults,
59 List *aggcombinefnName,
60 List *aggserialfnName,
61 List *aggdeserialfnName,
62 List *aggmtransfnName,
63 List *aggminvtransfnName,
64 List *aggmfinalfnName,
65 bool finalfnExtraArgs,
66 bool mfinalfnExtraArgs,
74 const char *agginitval,
75 const char *aggminitval,
80 bool nulls[Natts_pg_aggregate];
81 Datum values[Natts_pg_aggregate];
84 Oid finalfn = InvalidOid; /* can be omitted */
85 Oid combinefn = InvalidOid; /* can be omitted */
86 Oid serialfn = InvalidOid; /* can be omitted */
87 Oid deserialfn = InvalidOid; /* can be omitted */
88 Oid mtransfn = InvalidOid; /* can be omitted */
89 Oid minvtransfn = InvalidOid; /* can be omitted */
90 Oid mfinalfn = InvalidOid; /* can be omitted */
91 Oid sortop = InvalidOid; /* can be omitted */
92 Oid *aggArgTypes = parameterTypes->values;
95 bool mtransIsStrict = false;
98 Oid fnArgs[FUNC_MAX_ARGS];
104 ObjectAddress myself,
108 /* sanity checks (caller should have caught these) */
110 elog(ERROR, "no aggregate name supplied");
113 elog(ERROR, "aggregate must have a transition function");
115 if (numDirectArgs < 0 || numDirectArgs > numArgs)
116 elog(ERROR, "incorrect number of direct args for aggregate");
119 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
120 * and/or finalfn will be unrepresentable in pg_proc. We must check now
121 * to protect fixed-size arrays here and possibly in called functions.
123 if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
125 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
126 errmsg_plural("aggregates cannot have more than %d argument",
127 "aggregates cannot have more than %d arguments",
129 FUNC_MAX_ARGS - 1)));
131 /* check for polymorphic and INTERNAL arguments */
133 hasInternalArg = false;
134 for (i = 0; i < numArgs; i++)
136 if (IsPolymorphicType(aggArgTypes[i]))
138 else if (aggArgTypes[i] == INTERNALOID)
139 hasInternalArg = true;
143 * If transtype is polymorphic, must have polymorphic argument also; else
144 * we will have no way to deduce the actual transtype.
146 if (IsPolymorphicType(aggTransType) && !hasPolyArg)
148 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
149 errmsg("cannot determine transition data type"),
150 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
153 * Likewise for moving-aggregate transtype, if any
155 if (OidIsValid(aggmTransType) &&
156 IsPolymorphicType(aggmTransType) && !hasPolyArg)
158 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
159 errmsg("cannot determine transition data type"),
160 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
163 * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
164 * principle we could support regular variadic types, but it would make
165 * things much more complicated because we'd have to assemble the correct
166 * subsets of arguments into array values. Since no standard aggregates
167 * have use for such a case, we aren't bothering for now.
169 if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
170 variadicArgType != ANYOID)
172 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
173 errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
176 * If it's a hypothetical-set aggregate, there must be at least as many
177 * direct arguments as aggregated ones, and the last N direct arguments
178 * must match the aggregated ones in type. (We have to check this again
179 * when the aggregate is called, in case ANY is involved, but it makes
180 * sense to reject the aggregate definition now if the declared arg types
181 * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
182 * indicating that the grammar merged identical VARIADIC entries from both
183 * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
184 * the aggregated side, which is not OK. Otherwise, insist on the last N
185 * parameter types on each side matching exactly.
187 if (aggKind == AGGKIND_HYPOTHETICAL &&
188 numDirectArgs < numArgs)
190 int numAggregatedArgs = numArgs - numDirectArgs;
192 if (OidIsValid(variadicArgType) ||
193 numDirectArgs < numAggregatedArgs ||
194 memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
195 aggArgTypes + numDirectArgs,
196 numAggregatedArgs * sizeof(Oid)) != 0)
198 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
199 errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
203 * Find the transfn. For ordinary aggs, it takes the transtype plus all
204 * aggregate arguments. For ordered-set aggs, it takes the transtype plus
205 * all aggregated args, but not direct args. However, we have to treat
206 * specially the case where a trailing VARIADIC item is considered to
207 * cover both direct and aggregated args.
209 if (AGGKIND_IS_ORDERED_SET(aggKind))
211 if (numDirectArgs < numArgs)
212 nargs_transfn = numArgs - numDirectArgs + 1;
215 /* special case with VARIADIC last arg */
216 Assert(variadicArgType != InvalidOid);
219 fnArgs[0] = aggTransType;
220 memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
221 (nargs_transfn - 1) * sizeof(Oid));
225 nargs_transfn = numArgs + 1;
226 fnArgs[0] = aggTransType;
227 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
229 transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
230 fnArgs, variadicArgType,
234 * Return type of transfn (possibly after refinement by
235 * enforce_generic_type_consistency, if transtype isn't polymorphic) must
236 * exactly match declared transtype.
238 * In the non-polymorphic-transtype case, it might be okay to allow a
239 * rettype that's binary-coercible to transtype, but I'm not quite
240 * convinced that it's either safe or useful. When transtype is
241 * polymorphic we *must* demand exact equality.
243 if (rettype != aggTransType)
245 (errcode(ERRCODE_DATATYPE_MISMATCH),
246 errmsg("return type of transition function %s is not %s",
247 NameListToString(aggtransfnName),
248 format_type_be(aggTransType))));
250 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
251 if (!HeapTupleIsValid(tup))
252 elog(ERROR, "cache lookup failed for function %u", transfn);
253 proc = (Form_pg_proc) GETSTRUCT(tup);
256 * If the transfn is strict and the initval is NULL, make sure first input
257 * type and transtype are the same (or at least binary-compatible), so
258 * that it's OK to use the first input value as the initial transValue.
260 if (proc->proisstrict && agginitval == NULL)
263 !IsBinaryCoercible(aggArgTypes[0], aggTransType))
265 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
266 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
269 ReleaseSysCache(tup);
271 /* handle moving-aggregate transfn, if supplied */
275 * The arguments are the same as for the regular transfn, except that
276 * the transition data type might be different. So re-use the fnArgs
277 * values set up above, except for that one.
279 Assert(OidIsValid(aggmTransType));
280 fnArgs[0] = aggmTransType;
282 mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
283 fnArgs, variadicArgType,
286 /* As above, return type must exactly match declared mtranstype. */
287 if (rettype != aggmTransType)
289 (errcode(ERRCODE_DATATYPE_MISMATCH),
290 errmsg("return type of transition function %s is not %s",
291 NameListToString(aggmtransfnName),
292 format_type_be(aggmTransType))));
294 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
295 if (!HeapTupleIsValid(tup))
296 elog(ERROR, "cache lookup failed for function %u", mtransfn);
297 proc = (Form_pg_proc) GETSTRUCT(tup);
300 * If the mtransfn is strict and the minitval is NULL, check first
301 * input type and mtranstype are binary-compatible.
303 if (proc->proisstrict && aggminitval == NULL)
306 !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
308 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
309 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
312 /* Remember if mtransfn is strict; we may need this below */
313 mtransIsStrict = proc->proisstrict;
315 ReleaseSysCache(tup);
318 /* handle minvtransfn, if supplied */
319 if (aggminvtransfnName)
322 * This must have the same number of arguments with the same types as
323 * the forward transition function, so just re-use the fnArgs data.
325 Assert(aggmtransfnName);
327 minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
328 fnArgs, variadicArgType,
331 /* As above, return type must exactly match declared mtranstype. */
332 if (rettype != aggmTransType)
334 (errcode(ERRCODE_DATATYPE_MISMATCH),
335 errmsg("return type of inverse transition function %s is not %s",
336 NameListToString(aggminvtransfnName),
337 format_type_be(aggmTransType))));
339 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
340 if (!HeapTupleIsValid(tup))
341 elog(ERROR, "cache lookup failed for function %u", minvtransfn);
342 proc = (Form_pg_proc) GETSTRUCT(tup);
345 * We require the strictness settings of the forward and inverse
346 * transition functions to agree. This saves having to handle
347 * assorted special cases at execution time.
349 if (proc->proisstrict != mtransIsStrict)
351 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
352 errmsg("strictness of aggregate's forward and inverse transition functions must match")));
354 ReleaseSysCache(tup);
357 /* handle finalfn, if supplied */
361 * If finalfnExtraArgs is specified, the transfn takes the transtype
362 * plus all args; otherwise, it just takes the transtype plus any
363 * direct args. (Non-direct args are useless at runtime, and are
364 * actually passed as NULLs, but we may need them in the function
365 * signature to allow resolution of a polymorphic agg's result type.)
367 Oid ffnVariadicArgType = variadicArgType;
369 fnArgs[0] = aggTransType;
370 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
371 if (finalfnExtraArgs)
372 nargs_finalfn = numArgs + 1;
375 nargs_finalfn = numDirectArgs + 1;
376 if (numDirectArgs < numArgs)
378 /* variadic argument doesn't affect finalfn */
379 ffnVariadicArgType = InvalidOid;
383 finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
384 fnArgs, ffnVariadicArgType,
388 * When finalfnExtraArgs is specified, the finalfn will certainly be
389 * passed at least one null argument, so complain if it's strict.
390 * Nothing bad would happen at runtime (you'd just get a null result),
391 * but it's surely not what the user wants, so let's complain now.
393 if (finalfnExtraArgs && func_strict(finalfn))
395 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
396 errmsg("final function with extra arguments must not be declared STRICT")));
401 * If no finalfn, aggregate result type is type of the state value
403 finaltype = aggTransType;
405 Assert(OidIsValid(finaltype));
407 /* handle the combinefn, if supplied */
408 if (aggcombinefnName)
413 * Combine function must have 2 arguments, each of which is the trans
414 * type. VARIADIC doesn't affect it.
416 fnArgs[0] = aggTransType;
417 fnArgs[1] = aggTransType;
419 combinefn = lookup_agg_function(aggcombinefnName, 2,
423 /* Ensure the return type matches the aggregate's trans type */
424 if (combineType != aggTransType)
426 (errcode(ERRCODE_DATATYPE_MISMATCH),
427 errmsg("return type of combine function %s is not %s",
428 NameListToString(aggcombinefnName),
429 format_type_be(aggTransType))));
432 * A combine function to combine INTERNAL states must accept nulls and
433 * ensure that the returned state is in the correct memory context. We
434 * cannot directly check the latter, but we can check the former.
436 if (aggTransType == INTERNALOID && func_strict(combinefn))
438 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
439 errmsg("combine function with transition type %s must not be declared STRICT",
440 format_type_be(aggTransType))));
444 * Validate the serialization function, if present.
448 /* signature is always serialize(internal) returns bytea */
449 fnArgs[0] = INTERNALOID;
451 serialfn = lookup_agg_function(aggserialfnName, 1,
455 if (rettype != BYTEAOID)
457 (errcode(ERRCODE_DATATYPE_MISMATCH),
458 errmsg("return type of serialization function %s is not %s",
459 NameListToString(aggserialfnName),
460 format_type_be(BYTEAOID))));
464 * Validate the deserialization function, if present.
466 if (aggdeserialfnName)
468 /* signature is always deserialize(bytea, internal) returns internal */
469 fnArgs[0] = BYTEAOID;
470 fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
472 deserialfn = lookup_agg_function(aggdeserialfnName, 2,
476 if (rettype != INTERNALOID)
478 (errcode(ERRCODE_DATATYPE_MISMATCH),
479 errmsg("return type of deserialization function %s is not %s",
480 NameListToString(aggdeserialfnName),
481 format_type_be(INTERNALOID))));
485 * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
486 * be polymorphic also, else parser will fail to deduce result type.
487 * (Note: given the previous test on transtype and inputs, this cannot
488 * happen, unless someone has snuck a finalfn definition into the catalogs
489 * that itself violates the rule against polymorphic result with no
490 * polymorphic input.)
492 if (IsPolymorphicType(finaltype) && !hasPolyArg)
494 (errcode(ERRCODE_DATATYPE_MISMATCH),
495 errmsg("cannot determine result data type"),
496 errdetail("An aggregate returning a polymorphic type "
497 "must have at least one polymorphic argument.")));
500 * Also, the return type can't be INTERNAL unless there's at least one
501 * INTERNAL argument. This is the same type-safety restriction we enforce
502 * for regular functions, but at the level of aggregates. We must test
503 * this explicitly because we allow INTERNAL as the transtype.
505 if (finaltype == INTERNALOID && !hasInternalArg)
507 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
508 errmsg("unsafe use of pseudo-type \"internal\""),
509 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
512 * If a moving-aggregate implementation is supplied, look up its finalfn
513 * if any, and check that the implied aggregate result type matches the
514 * plain implementation.
516 if (OidIsValid(aggmTransType))
518 /* handle finalfn, if supplied */
522 * The arguments are figured the same way as for the regular
523 * finalfn, but using aggmTransType and mfinalfnExtraArgs.
525 Oid ffnVariadicArgType = variadicArgType;
527 fnArgs[0] = aggmTransType;
528 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
529 if (mfinalfnExtraArgs)
530 nargs_finalfn = numArgs + 1;
533 nargs_finalfn = numDirectArgs + 1;
534 if (numDirectArgs < numArgs)
536 /* variadic argument doesn't affect finalfn */
537 ffnVariadicArgType = InvalidOid;
541 mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
542 fnArgs, ffnVariadicArgType,
545 /* As above, check strictness if mfinalfnExtraArgs is given */
546 if (mfinalfnExtraArgs && func_strict(mfinalfn))
548 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
549 errmsg("final function with extra arguments must not be declared STRICT")));
554 * If no finalfn, aggregate result type is type of the state value
556 rettype = aggmTransType;
558 Assert(OidIsValid(rettype));
559 if (rettype != finaltype)
561 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
562 errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
563 format_type_be(aggmTransType),
564 format_type_be(aggTransType))));
567 /* handle sortop, if supplied */
572 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
573 errmsg("sort operator can only be specified for single-argument aggregates")));
574 sortop = LookupOperName(NULL, aggsortopName,
575 aggArgTypes[0], aggArgTypes[0],
580 * permission checks on used types
582 for (i = 0; i < numArgs; i++)
584 aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
585 if (aclresult != ACLCHECK_OK)
586 aclcheck_error_type(aclresult, aggArgTypes[i]);
589 aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
590 if (aclresult != ACLCHECK_OK)
591 aclcheck_error_type(aclresult, aggTransType);
593 if (OidIsValid(aggmTransType))
595 aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
596 if (aclresult != ACLCHECK_OK)
597 aclcheck_error_type(aclresult, aggmTransType);
600 aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
601 if (aclresult != ACLCHECK_OK)
602 aclcheck_error_type(aclresult, finaltype);
606 * Everything looks okay. Try to create the pg_proc entry for the
607 * aggregate. (This could fail if there's already a conflicting entry.)
610 myself = ProcedureCreate(aggName,
612 false, /* no replacement */
613 false, /* doesn't return a set */
614 finaltype, /* returnType */
615 GetUserId(), /* proowner */
616 INTERNALlanguageId, /* languageObjectId */
617 InvalidOid, /* no validator */
618 "aggregate_dummy", /* placeholder proc */
621 false, /* security invoker (currently not
622 * definable for agg) */
623 false, /* isLeakProof */
624 false, /* isStrict (not needed for agg) */
625 PROVOLATILE_IMMUTABLE, /* volatility (not needed
628 parameterTypes, /* paramTypes */
629 allParameterTypes, /* allParamTypes */
630 parameterModes, /* parameterModes */
631 parameterNames, /* parameterNames */
632 parameterDefaults, /* parameterDefaults */
633 PointerGetDatum(NULL), /* trftypes */
634 PointerGetDatum(NULL), /* proconfig */
637 procOid = myself.objectId;
640 * Okay to create the pg_aggregate entry.
642 aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
643 tupDesc = aggdesc->rd_att;
645 /* initialize nulls and values */
646 for (i = 0; i < Natts_pg_aggregate; i++)
649 values[i] = (Datum) NULL;
651 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
652 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
653 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
654 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
655 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
656 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
657 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
658 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
659 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
660 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
661 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
662 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
663 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
664 values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
665 values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
666 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
667 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
668 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
669 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
670 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
672 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
674 nulls[Anum_pg_aggregate_agginitval - 1] = true;
676 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
678 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
680 tup = heap_form_tuple(tupDesc, values, nulls);
681 CatalogTupleInsert(aggdesc, tup);
683 heap_close(aggdesc, RowExclusiveLock);
686 * Create dependencies for the aggregate (above and beyond those already
687 * made by ProcedureCreate). Note: we don't need an explicit dependency
688 * on aggTransType since we depend on it indirectly through transfn.
689 * Likewise for aggmTransType using the mtransfunc, if it exists.
692 /* Depends on transition function */
693 referenced.classId = ProcedureRelationId;
694 referenced.objectId = transfn;
695 referenced.objectSubId = 0;
696 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
698 /* Depends on final function, if any */
699 if (OidIsValid(finalfn))
701 referenced.classId = ProcedureRelationId;
702 referenced.objectId = finalfn;
703 referenced.objectSubId = 0;
704 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
707 /* Depends on combine function, if any */
708 if (OidIsValid(combinefn))
710 referenced.classId = ProcedureRelationId;
711 referenced.objectId = combinefn;
712 referenced.objectSubId = 0;
713 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
716 /* Depends on serialization function, if any */
717 if (OidIsValid(serialfn))
719 referenced.classId = ProcedureRelationId;
720 referenced.objectId = serialfn;
721 referenced.objectSubId = 0;
722 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
725 /* Depends on deserialization function, if any */
726 if (OidIsValid(deserialfn))
728 referenced.classId = ProcedureRelationId;
729 referenced.objectId = deserialfn;
730 referenced.objectSubId = 0;
731 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
734 /* Depends on forward transition function, if any */
735 if (OidIsValid(mtransfn))
737 referenced.classId = ProcedureRelationId;
738 referenced.objectId = mtransfn;
739 referenced.objectSubId = 0;
740 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
743 /* Depends on inverse transition function, if any */
744 if (OidIsValid(minvtransfn))
746 referenced.classId = ProcedureRelationId;
747 referenced.objectId = minvtransfn;
748 referenced.objectSubId = 0;
749 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
752 /* Depends on final function, if any */
753 if (OidIsValid(mfinalfn))
755 referenced.classId = ProcedureRelationId;
756 referenced.objectId = mfinalfn;
757 referenced.objectSubId = 0;
758 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
761 /* Depends on sort operator, if any */
762 if (OidIsValid(sortop))
764 referenced.classId = OperatorRelationId;
765 referenced.objectId = sortop;
766 referenced.objectSubId = 0;
767 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
774 * lookup_agg_function
775 * common code for finding aggregate support functions
777 * fnName: possibly-schema-qualified function name
778 * nargs, input_types: expected function argument types
779 * variadicArgType: type of variadic argument if any, else InvalidOid
781 * Returns OID of function, and stores its return type into *rettype
783 * NB: must not scribble on input_types[], as we may re-use those
786 lookup_agg_function(List *fnName,
797 FuncDetailCode fdresult;
802 * func_get_detail looks up the function in the catalogs, does
803 * disambiguation for polymorphic functions, handles inheritance, and
804 * returns the funcid and type and set or singleton status of the
805 * function's return value. it also returns the true argument types to
808 fdresult = func_get_detail(fnName, NIL, NIL,
809 nargs, input_types, false, false,
810 &fnOid, rettype, &retset,
812 &true_oid_array, NULL);
814 /* only valid case is a normal function not returning a set */
815 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
817 (errcode(ERRCODE_UNDEFINED_FUNCTION),
818 errmsg("function %s does not exist",
819 func_signature_string(fnName, nargs,
820 NIL, input_types))));
823 (errcode(ERRCODE_DATATYPE_MISMATCH),
824 errmsg("function %s returns a set",
825 func_signature_string(fnName, nargs,
826 NIL, input_types))));
829 * If the agg is declared to take VARIADIC ANY, the underlying functions
830 * had better be declared that way too, else they may receive too many
831 * parameters; but func_get_detail would have been happy with plain ANY.
832 * (Probably nothing very bad would happen, but it wouldn't work as the
833 * user expects.) Other combinations should work without any special
834 * pushups, given that we told func_get_detail not to expand VARIADIC.
836 if (variadicArgType == ANYOID && vatype != ANYOID)
838 (errcode(ERRCODE_DATATYPE_MISMATCH),
839 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
840 func_signature_string(fnName, nargs,
841 NIL, input_types))));
844 * If there are any polymorphic types involved, enforce consistency, and
845 * possibly refine the result type. It's OK if the result is still
846 * polymorphic at this point, though.
848 *rettype = enforce_generic_type_consistency(input_types,
855 * func_get_detail will find functions requiring run-time argument type
856 * coercion, but nodeAgg.c isn't prepared to deal with that
858 for (i = 0; i < nargs; i++)
860 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
862 (errcode(ERRCODE_DATATYPE_MISMATCH),
863 errmsg("function %s requires run-time type coercion",
864 func_signature_string(fnName, nargs,
865 NIL, true_oid_array))));
868 /* Check aggregate creator has permission to call the function */
869 aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
870 if (aclresult != ACLCHECK_OK)
871 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));