PostgreSQL Source Code git master
pg_aggregate.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_aggregate.c
4 * routines to support manipulation of the pg_aggregate relation
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_aggregate.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include "access/htup_details.h"
18#include "access/table.h"
19#include "catalog/dependency.h"
20#include "catalog/indexing.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"
35
36
37static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
38 Oid variadicArgType,
39 Oid *rettype);
40
41
42/*
43 * AggregateCreate
44 */
46AggregateCreate(const char *aggName,
47 Oid aggNamespace,
48 bool replace,
49 char aggKind,
50 int numArgs,
51 int numDirectArgs,
52 oidvector *parameterTypes,
53 Datum allParameterTypes,
54 Datum parameterModes,
55 Datum parameterNames,
56 List *parameterDefaults,
57 Oid variadicArgType,
58 List *aggtransfnName,
59 List *aggfinalfnName,
60 List *aggcombinefnName,
61 List *aggserialfnName,
62 List *aggdeserialfnName,
63 List *aggmtransfnName,
64 List *aggminvtransfnName,
65 List *aggmfinalfnName,
66 bool finalfnExtraArgs,
67 bool mfinalfnExtraArgs,
68 char finalfnModify,
69 char mfinalfnModify,
70 List *aggsortopName,
71 Oid aggTransType,
72 int32 aggTransSpace,
73 Oid aggmTransType,
74 int32 aggmTransSpace,
75 const char *agginitval,
76 const char *aggminitval,
77 char proparallel)
78{
79 Relation aggdesc;
80 HeapTuple tup;
81 HeapTuple oldtup;
82 bool nulls[Natts_pg_aggregate];
83 Datum values[Natts_pg_aggregate];
84 bool replaces[Natts_pg_aggregate];
85 Form_pg_proc proc;
86 Oid transfn;
87 Oid finalfn = InvalidOid; /* can be omitted */
88 Oid combinefn = InvalidOid; /* can be omitted */
89 Oid serialfn = InvalidOid; /* can be omitted */
90 Oid deserialfn = InvalidOid; /* can be omitted */
91 Oid mtransfn = InvalidOid; /* can be omitted */
92 Oid minvtransfn = InvalidOid; /* can be omitted */
93 Oid mfinalfn = InvalidOid; /* can be omitted */
94 Oid sortop = InvalidOid; /* can be omitted */
95 Oid *aggArgTypes = parameterTypes->values;
96 bool mtransIsStrict = false;
97 Oid rettype;
98 Oid finaltype;
99 Oid fnArgs[FUNC_MAX_ARGS];
100 int nargs_transfn;
101 int nargs_finalfn;
102 Oid procOid;
103 TupleDesc tupDesc;
104 char *detailmsg;
105 int i;
106 ObjectAddress myself,
107 referenced;
108 ObjectAddresses *addrs;
109 AclResult aclresult;
110
111 /* sanity checks (caller should have caught these) */
112 if (!aggName)
113 elog(ERROR, "no aggregate name supplied");
114
115 if (!aggtransfnName)
116 elog(ERROR, "aggregate must have a transition function");
117
118 if (numDirectArgs < 0 || numDirectArgs > numArgs)
119 elog(ERROR, "incorrect number of direct arguments for aggregate");
120
121 /*
122 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
123 * and/or finalfn will be unrepresentable in pg_proc. We must check now
124 * to protect fixed-size arrays here and possibly in called functions.
125 */
126 if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
128 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
129 errmsg_plural("aggregates cannot have more than %d argument",
130 "aggregates cannot have more than %d arguments",
131 FUNC_MAX_ARGS - 1,
132 FUNC_MAX_ARGS - 1)));
133
134 /*
135 * If transtype is polymorphic, must have polymorphic argument also; else
136 * we will have no way to deduce the actual transtype.
137 */
138 detailmsg = check_valid_polymorphic_signature(aggTransType,
139 aggArgTypes,
140 numArgs);
141 if (detailmsg)
143 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
144 errmsg("cannot determine transition data type"),
145 errdetail_internal("%s", detailmsg)));
146
147 /*
148 * Likewise for moving-aggregate transtype, if any
149 */
150 if (OidIsValid(aggmTransType))
151 {
152 detailmsg = check_valid_polymorphic_signature(aggmTransType,
153 aggArgTypes,
154 numArgs);
155 if (detailmsg)
157 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158 errmsg("cannot determine transition data type"),
159 errdetail_internal("%s", detailmsg)));
160 }
161
162 /*
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.
168 */
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")));
174
175 /*
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.
186 */
187 if (aggKind == AGGKIND_HYPOTHETICAL &&
188 numDirectArgs < numArgs)
189 {
190 int numAggregatedArgs = numArgs - numDirectArgs;
191
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")));
200 }
201
202 /*
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.
208 */
209 if (AGGKIND_IS_ORDERED_SET(aggKind))
210 {
211 if (numDirectArgs < numArgs)
212 nargs_transfn = numArgs - numDirectArgs + 1;
213 else
214 {
215 /* special case with VARIADIC last arg */
216 Assert(variadicArgType != InvalidOid);
217 nargs_transfn = 2;
218 }
219 fnArgs[0] = aggTransType;
220 memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
221 (nargs_transfn - 1) * sizeof(Oid));
222 }
223 else
224 {
225 nargs_transfn = numArgs + 1;
226 fnArgs[0] = aggTransType;
227 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
228 }
229 transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
230 fnArgs, variadicArgType,
231 &rettype);
232
233 /*
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.
237 *
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.
242 */
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))));
249
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);
254
255 /*
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.
259 */
260 if (proc->proisstrict && agginitval == NULL)
261 {
262 if (numArgs < 1 ||
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")));
267 }
268
269 ReleaseSysCache(tup);
270
271 /* handle moving-aggregate transfn, if supplied */
272 if (aggmtransfnName)
273 {
274 /*
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.
278 */
279 Assert(OidIsValid(aggmTransType));
280 fnArgs[0] = aggmTransType;
281
282 mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
283 fnArgs, variadicArgType,
284 &rettype);
285
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))));
293
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);
298
299 /*
300 * If the mtransfn is strict and the minitval is NULL, check first
301 * input type and mtranstype are binary-compatible.
302 */
303 if (proc->proisstrict && aggminitval == NULL)
304 {
305 if (numArgs < 1 ||
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")));
310 }
311
312 /* Remember if mtransfn is strict; we may need this below */
313 mtransIsStrict = proc->proisstrict;
314
315 ReleaseSysCache(tup);
316 }
317
318 /* handle minvtransfn, if supplied */
319 if (aggminvtransfnName)
320 {
321 /*
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.
324 */
325 Assert(aggmtransfnName);
326
327 minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
328 fnArgs, variadicArgType,
329 &rettype);
330
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))));
338
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);
343
344 /*
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.
348 */
349 if (proc->proisstrict != mtransIsStrict)
351 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
352 errmsg("strictness of aggregate's forward and inverse transition functions must match")));
353
354 ReleaseSysCache(tup);
355 }
356
357 /* handle finalfn, if supplied */
358 if (aggfinalfnName)
359 {
360 /*
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.)
366 */
367 Oid ffnVariadicArgType = variadicArgType;
368
369 fnArgs[0] = aggTransType;
370 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
371 if (finalfnExtraArgs)
372 nargs_finalfn = numArgs + 1;
373 else
374 {
375 nargs_finalfn = numDirectArgs + 1;
376 if (numDirectArgs < numArgs)
377 {
378 /* variadic argument doesn't affect finalfn */
379 ffnVariadicArgType = InvalidOid;
380 }
381 }
382
383 finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
384 fnArgs, ffnVariadicArgType,
385 &finaltype);
386
387 /*
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.
392 */
393 if (finalfnExtraArgs && func_strict(finalfn))
395 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
396 errmsg("final function with extra arguments must not be declared STRICT")));
397 }
398 else
399 {
400 /*
401 * If no finalfn, aggregate result type is type of the state value
402 */
403 finaltype = aggTransType;
404 }
405 Assert(OidIsValid(finaltype));
406
407 /* handle the combinefn, if supplied */
408 if (aggcombinefnName)
409 {
410 Oid combineType;
411
412 /*
413 * Combine function must have 2 arguments, each of which is the trans
414 * type. VARIADIC doesn't affect it.
415 */
416 fnArgs[0] = aggTransType;
417 fnArgs[1] = aggTransType;
418
419 combinefn = lookup_agg_function(aggcombinefnName, 2,
420 fnArgs, InvalidOid,
421 &combineType);
422
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))));
430
431 /*
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.
435 */
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))));
441 }
442
443 /*
444 * Validate the serialization function, if present.
445 */
446 if (aggserialfnName)
447 {
448 /* signature is always serialize(internal) returns bytea */
449 fnArgs[0] = INTERNALOID;
450
451 serialfn = lookup_agg_function(aggserialfnName, 1,
452 fnArgs, InvalidOid,
453 &rettype);
454
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))));
461 }
462
463 /*
464 * Validate the deserialization function, if present.
465 */
466 if (aggdeserialfnName)
467 {
468 /* signature is always deserialize(bytea, internal) returns internal */
469 fnArgs[0] = BYTEAOID;
470 fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
471
472 deserialfn = lookup_agg_function(aggdeserialfnName, 2,
473 fnArgs, InvalidOid,
474 &rettype);
475
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))));
482 }
483
484 /*
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.)
491 */
492 detailmsg = check_valid_polymorphic_signature(finaltype,
493 aggArgTypes,
494 numArgs);
495 if (detailmsg)
497 (errcode(ERRCODE_DATATYPE_MISMATCH),
498 errmsg("cannot determine result data type"),
499 errdetail_internal("%s", detailmsg)));
500
501 /*
502 * Also, the return type can't be INTERNAL unless there's at least one
503 * INTERNAL argument. This is the same type-safety restriction we enforce
504 * for regular functions, but at the level of aggregates. We must test
505 * this explicitly because we allow INTERNAL as the transtype.
506 */
507 detailmsg = check_valid_internal_signature(finaltype,
508 aggArgTypes,
509 numArgs);
510 if (detailmsg)
512 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
513 errmsg("unsafe use of pseudo-type \"internal\""),
514 errdetail_internal("%s", detailmsg)));
515
516 /*
517 * If a moving-aggregate implementation is supplied, look up its finalfn
518 * if any, and check that the implied aggregate result type matches the
519 * plain implementation.
520 */
521 if (OidIsValid(aggmTransType))
522 {
523 /* handle finalfn, if supplied */
524 if (aggmfinalfnName)
525 {
526 /*
527 * The arguments are figured the same way as for the regular
528 * finalfn, but using aggmTransType and mfinalfnExtraArgs.
529 */
530 Oid ffnVariadicArgType = variadicArgType;
531
532 fnArgs[0] = aggmTransType;
533 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
534 if (mfinalfnExtraArgs)
535 nargs_finalfn = numArgs + 1;
536 else
537 {
538 nargs_finalfn = numDirectArgs + 1;
539 if (numDirectArgs < numArgs)
540 {
541 /* variadic argument doesn't affect finalfn */
542 ffnVariadicArgType = InvalidOid;
543 }
544 }
545
546 mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
547 fnArgs, ffnVariadicArgType,
548 &rettype);
549
550 /* As above, check strictness if mfinalfnExtraArgs is given */
551 if (mfinalfnExtraArgs && func_strict(mfinalfn))
553 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
554 errmsg("final function with extra arguments must not be declared STRICT")));
555 }
556 else
557 {
558 /*
559 * If no finalfn, aggregate result type is type of the state value
560 */
561 rettype = aggmTransType;
562 }
563 Assert(OidIsValid(rettype));
564 if (rettype != finaltype)
566 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
567 errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
568 format_type_be(rettype),
569 format_type_be(finaltype))));
570 }
571
572 /* handle sortop, if supplied */
573 if (aggsortopName)
574 {
575 if (numArgs != 1)
577 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
578 errmsg("sort operator can only be specified for single-argument aggregates")));
579 sortop = LookupOperName(NULL, aggsortopName,
580 aggArgTypes[0], aggArgTypes[0],
581 false, -1);
582 }
583
584 /*
585 * permission checks on used types
586 */
587 for (i = 0; i < numArgs; i++)
588 {
589 aclresult = object_aclcheck(TypeRelationId, aggArgTypes[i], GetUserId(), ACL_USAGE);
590 if (aclresult != ACLCHECK_OK)
591 aclcheck_error_type(aclresult, aggArgTypes[i]);
592 }
593
594 aclresult = object_aclcheck(TypeRelationId, aggTransType, GetUserId(), ACL_USAGE);
595 if (aclresult != ACLCHECK_OK)
596 aclcheck_error_type(aclresult, aggTransType);
597
598 if (OidIsValid(aggmTransType))
599 {
600 aclresult = object_aclcheck(TypeRelationId, aggmTransType, GetUserId(), ACL_USAGE);
601 if (aclresult != ACLCHECK_OK)
602 aclcheck_error_type(aclresult, aggmTransType);
603 }
604
605 aclresult = object_aclcheck(TypeRelationId, finaltype, GetUserId(), ACL_USAGE);
606 if (aclresult != ACLCHECK_OK)
607 aclcheck_error_type(aclresult, finaltype);
608
609
610 /*
611 * Everything looks okay. Try to create the pg_proc entry for the
612 * aggregate. (This could fail if there's already a conflicting entry.)
613 */
614
615 myself = ProcedureCreate(aggName,
616 aggNamespace,
617 replace, /* maybe replacement */
618 false, /* doesn't return a set */
619 finaltype, /* returnType */
620 GetUserId(), /* proowner */
621 INTERNALlanguageId, /* languageObjectId */
622 InvalidOid, /* no validator */
623 "aggregate_dummy", /* placeholder (no such proc) */
624 NULL, /* probin */
625 NULL, /* prosqlbody */
626 PROKIND_AGGREGATE,
627 false, /* security invoker (currently not
628 * definable for agg) */
629 false, /* isLeakProof */
630 false, /* isStrict (not needed for agg) */
631 PROVOLATILE_IMMUTABLE, /* volatility (not needed
632 * for agg) */
633 proparallel,
634 parameterTypes, /* paramTypes */
635 allParameterTypes, /* allParamTypes */
636 parameterModes, /* parameterModes */
637 parameterNames, /* parameterNames */
638 parameterDefaults, /* parameterDefaults */
639 PointerGetDatum(NULL), /* trftypes */
640 PointerGetDatum(NULL), /* proconfig */
641 InvalidOid, /* no prosupport */
642 1, /* procost */
643 0); /* prorows */
644 procOid = myself.objectId;
645
646 /*
647 * Okay to create the pg_aggregate entry.
648 */
649 aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
650 tupDesc = aggdesc->rd_att;
651
652 /* initialize nulls and values */
653 for (i = 0; i < Natts_pg_aggregate; i++)
654 {
655 nulls[i] = false;
656 values[i] = (Datum) NULL;
657 replaces[i] = true;
658 }
659 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
660 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
661 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
662 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
663 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
664 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
665 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
666 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
667 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
668 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
669 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
670 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
671 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
672 values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
673 values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
674 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
675 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
676 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
677 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
678 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
679 if (agginitval)
680 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
681 else
682 nulls[Anum_pg_aggregate_agginitval - 1] = true;
683 if (aggminitval)
684 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
685 else
686 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
687
688 if (replace)
689 oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
690 else
691 oldtup = NULL;
692
693 if (HeapTupleIsValid(oldtup))
694 {
696
697 /*
698 * If we're replacing an existing entry, we need to validate that
699 * we're not changing anything that would break callers. Specifically
700 * we must not change aggkind or aggnumdirectargs, which affect how an
701 * aggregate call is treated in parse analysis.
702 */
703 if (aggKind != oldagg->aggkind)
705 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
706 errmsg("cannot change routine kind"),
707 (oldagg->aggkind == AGGKIND_NORMAL ?
708 errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
709 oldagg->aggkind == AGGKIND_ORDERED_SET ?
710 errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
711 oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
712 errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
713 0)));
714 if (numDirectArgs != oldagg->aggnumdirectargs)
716 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
717 errmsg("cannot change number of direct arguments of an aggregate function")));
718
719 replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
720 replaces[Anum_pg_aggregate_aggkind - 1] = false;
721 replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
722
723 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
724 CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
725 ReleaseSysCache(oldtup);
726 }
727 else
728 {
729 tup = heap_form_tuple(tupDesc, values, nulls);
730 CatalogTupleInsert(aggdesc, tup);
731 }
732
734
735 /*
736 * Create dependencies for the aggregate (above and beyond those already
737 * made by ProcedureCreate). Note: we don't need an explicit dependency
738 * on aggTransType since we depend on it indirectly through transfn.
739 * Likewise for aggmTransType using the mtransfn, if it exists.
740 *
741 * If we're replacing an existing definition, ProcedureCreate deleted all
742 * our existing dependencies, so we have to do the same things here either
743 * way.
744 */
745
746 addrs = new_object_addresses();
747
748 /* Depends on transition function */
749 ObjectAddressSet(referenced, ProcedureRelationId, transfn);
750 add_exact_object_address(&referenced, addrs);
751
752 /* Depends on final function, if any */
753 if (OidIsValid(finalfn))
754 {
755 ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
756 add_exact_object_address(&referenced, addrs);
757 }
758
759 /* Depends on combine function, if any */
760 if (OidIsValid(combinefn))
761 {
762 ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
763 add_exact_object_address(&referenced, addrs);
764 }
765
766 /* Depends on serialization function, if any */
767 if (OidIsValid(serialfn))
768 {
769 ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
770 add_exact_object_address(&referenced, addrs);
771 }
772
773 /* Depends on deserialization function, if any */
774 if (OidIsValid(deserialfn))
775 {
776 ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
777 add_exact_object_address(&referenced, addrs);
778 }
779
780 /* Depends on forward transition function, if any */
781 if (OidIsValid(mtransfn))
782 {
783 ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
784 add_exact_object_address(&referenced, addrs);
785 }
786
787 /* Depends on inverse transition function, if any */
788 if (OidIsValid(minvtransfn))
789 {
790 ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
791 add_exact_object_address(&referenced, addrs);
792 }
793
794 /* Depends on final function, if any */
795 if (OidIsValid(mfinalfn))
796 {
797 ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
798 add_exact_object_address(&referenced, addrs);
799 }
800
801 /* Depends on sort operator, if any */
802 if (OidIsValid(sortop))
803 {
804 ObjectAddressSet(referenced, OperatorRelationId, sortop);
805 add_exact_object_address(&referenced, addrs);
806 }
807
810 return myself;
811}
812
813/*
814 * lookup_agg_function
815 * common code for finding aggregate support functions
816 *
817 * fnName: possibly-schema-qualified function name
818 * nargs, input_types: expected function argument types
819 * variadicArgType: type of variadic argument if any, else InvalidOid
820 *
821 * Returns OID of function, and stores its return type into *rettype
822 *
823 * NB: must not scribble on input_types[], as we may re-use those
824 */
825static Oid
827 int nargs,
828 Oid *input_types,
829 Oid variadicArgType,
830 Oid *rettype)
831{
832 Oid fnOid;
833 bool retset;
834 int nvargs;
835 Oid vatype;
836 Oid *true_oid_array;
837 FuncDetailCode fdresult;
838 AclResult aclresult;
839 int i;
840
841 /*
842 * func_get_detail looks up the function in the catalogs, does
843 * disambiguation for polymorphic functions, handles inheritance, and
844 * returns the funcid and type and set or singleton status of the
845 * function's return value. it also returns the true argument types to
846 * the function.
847 */
848 fdresult = func_get_detail(fnName, NIL, NIL,
849 nargs, input_types, false, false, false,
850 &fnOid, rettype, &retset,
851 &nvargs, &vatype,
852 &true_oid_array, NULL);
853
854 /* only valid case is a normal function not returning a set */
855 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
857 (errcode(ERRCODE_UNDEFINED_FUNCTION),
858 errmsg("function %s does not exist",
859 func_signature_string(fnName, nargs,
860 NIL, input_types))));
861 if (retset)
863 (errcode(ERRCODE_DATATYPE_MISMATCH),
864 errmsg("function %s returns a set",
865 func_signature_string(fnName, nargs,
866 NIL, input_types))));
867
868 /*
869 * If the agg is declared to take VARIADIC ANY, the underlying functions
870 * had better be declared that way too, else they may receive too many
871 * parameters; but func_get_detail would have been happy with plain ANY.
872 * (Probably nothing very bad would happen, but it wouldn't work as the
873 * user expects.) Other combinations should work without any special
874 * pushups, given that we told func_get_detail not to expand VARIADIC.
875 */
876 if (variadicArgType == ANYOID && vatype != ANYOID)
878 (errcode(ERRCODE_DATATYPE_MISMATCH),
879 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
880 func_signature_string(fnName, nargs,
881 NIL, input_types))));
882
883 /*
884 * If there are any polymorphic types involved, enforce consistency, and
885 * possibly refine the result type. It's OK if the result is still
886 * polymorphic at this point, though.
887 */
888 *rettype = enforce_generic_type_consistency(input_types,
889 true_oid_array,
890 nargs,
891 *rettype,
892 true);
893
894 /*
895 * func_get_detail will find functions requiring run-time argument type
896 * coercion, but nodeAgg.c isn't prepared to deal with that
897 */
898 for (i = 0; i < nargs; i++)
899 {
900 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
902 (errcode(ERRCODE_DATATYPE_MISMATCH),
903 errmsg("function %s requires run-time type coercion",
904 func_signature_string(fnName, nargs,
905 NIL, true_oid_array))));
906 }
907
908 /* Check aggregate creator has permission to call the function */
909 aclresult = object_aclcheck(ProcedureRelationId, fnOid, GetUserId(), ACL_EXECUTE);
910 if (aclresult != ACLCHECK_OK)
911 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
912
913 return fnOid;
914}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2941
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
#define OidIsValid(objectId)
Definition: c.h:732
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:72
#define RowExclusiveLock
Definition: lockdefs.h:38
bool func_strict(Oid funcid)
Definition: lsyscache.c:1761
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
Oid GetUserId(void)
Definition: miscinit.c:517
char * NameListToString(const List *names)
Definition: namespace.c:3594
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2030
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1395
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:99
#define ACL_USAGE
Definition: parsenodes.h:84
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
#define ACL_EXECUTE
Definition: parsenodes.h:83
ObjectAddress AggregateCreate(const char *aggName, Oid aggNamespace, bool replace, char aggKind, int numArgs, int numDirectArgs, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Oid variadicArgType, List *aggtransfnName, List *aggfinalfnName, List *aggcombinefnName, List *aggserialfnName, List *aggdeserialfnName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, char finalfnModify, char mfinalfnModify, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
Definition: pg_aggregate.c:46
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:826
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
#define NIL
Definition: pg_list.h:68
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:70
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:683
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:690
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40