1 /*-------------------------------------------------------------------------
2 *
3 * pg_aggregate.c
4 * routines to support manipulation of the pg_aggregate relation
5 *
6 * Portions Copyright (c) 1996-2020, 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"
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"
35
36
37 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
38 Oid variadicArgType,
39 Oid *rettype);
40
41
42 /*
43 * AggregateCreate
44 */
45 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)46 AggregateCreate(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 AclResult aclresult;
109
110 /* sanity checks (caller should have caught these) */
111 if (!aggName)
112 elog(ERROR, "no aggregate name supplied");
113
114 if (!aggtransfnName)
115 elog(ERROR, "aggregate must have a transition function");
116
117 if (numDirectArgs < 0 || numDirectArgs > numArgs)
118 elog(ERROR, "incorrect number of direct arguments for aggregate");
119
120 /*
121 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
122 * and/or finalfn will be unrepresentable in pg_proc. We must check now
123 * to protect fixed-size arrays here and possibly in called functions.
124 */
125 if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
126 ereport(ERROR,
127 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
128 errmsg_plural("aggregates cannot have more than %d argument",
129 "aggregates cannot have more than %d arguments",
130 FUNC_MAX_ARGS - 1,
131 FUNC_MAX_ARGS - 1)));
132
133 /*
134 * If transtype is polymorphic, must have polymorphic argument also; else
135 * we will have no way to deduce the actual transtype.
136 */
137 detailmsg = check_valid_polymorphic_signature(aggTransType,
138 aggArgTypes,
139 numArgs);
140 if (detailmsg)
141 ereport(ERROR,
142 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
143 errmsg("cannot determine transition data type"),
144 errdetail_internal("%s", detailmsg)));
145
146 /*
147 * Likewise for moving-aggregate transtype, if any
148 */
149 if (OidIsValid(aggmTransType))
150 {
151 detailmsg = check_valid_polymorphic_signature(aggmTransType,
152 aggArgTypes,
153 numArgs);
154 if (detailmsg)
155 ereport(ERROR,
156 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
157 errmsg("cannot determine transition data type"),
158 errdetail_internal("%s", detailmsg)));
159 }
160
161 /*
162 * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
163 * principle we could support regular variadic types, but it would make
164 * things much more complicated because we'd have to assemble the correct
165 * subsets of arguments into array values. Since no standard aggregates
166 * have use for such a case, we aren't bothering for now.
167 */
168 if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
169 variadicArgType != ANYOID)
170 ereport(ERROR,
171 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
172 errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
173
174 /*
175 * If it's a hypothetical-set aggregate, there must be at least as many
176 * direct arguments as aggregated ones, and the last N direct arguments
177 * must match the aggregated ones in type. (We have to check this again
178 * when the aggregate is called, in case ANY is involved, but it makes
179 * sense to reject the aggregate definition now if the declared arg types
180 * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
181 * indicating that the grammar merged identical VARIADIC entries from both
182 * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
183 * the aggregated side, which is not OK. Otherwise, insist on the last N
184 * parameter types on each side matching exactly.
185 */
186 if (aggKind == AGGKIND_HYPOTHETICAL &&
187 numDirectArgs < numArgs)
188 {
189 int numAggregatedArgs = numArgs - numDirectArgs;
190
191 if (OidIsValid(variadicArgType) ||
192 numDirectArgs < numAggregatedArgs ||
193 memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
194 aggArgTypes + numDirectArgs,
195 numAggregatedArgs * sizeof(Oid)) != 0)
196 ereport(ERROR,
197 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
198 errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
199 }
200
201 /*
202 * Find the transfn. For ordinary aggs, it takes the transtype plus all
203 * aggregate arguments. For ordered-set aggs, it takes the transtype plus
204 * all aggregated args, but not direct args. However, we have to treat
205 * specially the case where a trailing VARIADIC item is considered to
206 * cover both direct and aggregated args.
207 */
208 if (AGGKIND_IS_ORDERED_SET(aggKind))
209 {
210 if (numDirectArgs < numArgs)
211 nargs_transfn = numArgs - numDirectArgs + 1;
212 else
213 {
214 /* special case with VARIADIC last arg */
215 Assert(variadicArgType != InvalidOid);
216 nargs_transfn = 2;
217 }
218 fnArgs[0] = aggTransType;
219 memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
220 (nargs_transfn - 1) * sizeof(Oid));
221 }
222 else
223 {
224 nargs_transfn = numArgs + 1;
225 fnArgs[0] = aggTransType;
226 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
227 }
228 transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
229 fnArgs, variadicArgType,
230 &rettype);
231
232 /*
233 * Return type of transfn (possibly after refinement by
234 * enforce_generic_type_consistency, if transtype isn't polymorphic) must
235 * exactly match declared transtype.
236 *
237 * In the non-polymorphic-transtype case, it might be okay to allow a
238 * rettype that's binary-coercible to transtype, but I'm not quite
239 * convinced that it's either safe or useful. When transtype is
240 * polymorphic we *must* demand exact equality.
241 */
242 if (rettype != aggTransType)
243 ereport(ERROR,
244 (errcode(ERRCODE_DATATYPE_MISMATCH),
245 errmsg("return type of transition function %s is not %s",
246 NameListToString(aggtransfnName),
247 format_type_be(aggTransType))));
248
249 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
250 if (!HeapTupleIsValid(tup))
251 elog(ERROR, "cache lookup failed for function %u", transfn);
252 proc = (Form_pg_proc) GETSTRUCT(tup);
253
254 /*
255 * If the transfn is strict and the initval is NULL, make sure first input
256 * type and transtype are the same (or at least binary-compatible), so
257 * that it's OK to use the first input value as the initial transValue.
258 */
259 if (proc->proisstrict && agginitval == NULL)
260 {
261 if (numArgs < 1 ||
262 !IsBinaryCoercible(aggArgTypes[0], aggTransType))
263 ereport(ERROR,
264 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
265 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
266 }
267
268 ReleaseSysCache(tup);
269
270 /* handle moving-aggregate transfn, if supplied */
271 if (aggmtransfnName)
272 {
273 /*
274 * The arguments are the same as for the regular transfn, except that
275 * the transition data type might be different. So re-use the fnArgs
276 * values set up above, except for that one.
277 */
278 Assert(OidIsValid(aggmTransType));
279 fnArgs[0] = aggmTransType;
280
281 mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
282 fnArgs, variadicArgType,
283 &rettype);
284
285 /* As above, return type must exactly match declared mtranstype. */
286 if (rettype != aggmTransType)
287 ereport(ERROR,
288 (errcode(ERRCODE_DATATYPE_MISMATCH),
289 errmsg("return type of transition function %s is not %s",
290 NameListToString(aggmtransfnName),
291 format_type_be(aggmTransType))));
292
293 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
294 if (!HeapTupleIsValid(tup))
295 elog(ERROR, "cache lookup failed for function %u", mtransfn);
296 proc = (Form_pg_proc) GETSTRUCT(tup);
297
298 /*
299 * If the mtransfn is strict and the minitval is NULL, check first
300 * input type and mtranstype are binary-compatible.
301 */
302 if (proc->proisstrict && aggminitval == NULL)
303 {
304 if (numArgs < 1 ||
305 !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
306 ereport(ERROR,
307 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
308 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
309 }
310
311 /* Remember if mtransfn is strict; we may need this below */
312 mtransIsStrict = proc->proisstrict;
313
314 ReleaseSysCache(tup);
315 }
316
317 /* handle minvtransfn, if supplied */
318 if (aggminvtransfnName)
319 {
320 /*
321 * This must have the same number of arguments with the same types as
322 * the forward transition function, so just re-use the fnArgs data.
323 */
324 Assert(aggmtransfnName);
325
326 minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
327 fnArgs, variadicArgType,
328 &rettype);
329
330 /* As above, return type must exactly match declared mtranstype. */
331 if (rettype != aggmTransType)
332 ereport(ERROR,
333 (errcode(ERRCODE_DATATYPE_MISMATCH),
334 errmsg("return type of inverse transition function %s is not %s",
335 NameListToString(aggminvtransfnName),
336 format_type_be(aggmTransType))));
337
338 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
339 if (!HeapTupleIsValid(tup))
340 elog(ERROR, "cache lookup failed for function %u", minvtransfn);
341 proc = (Form_pg_proc) GETSTRUCT(tup);
342
343 /*
344 * We require the strictness settings of the forward and inverse
345 * transition functions to agree. This saves having to handle
346 * assorted special cases at execution time.
347 */
348 if (proc->proisstrict != mtransIsStrict)
349 ereport(ERROR,
350 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351 errmsg("strictness of aggregate's forward and inverse transition functions must match")));
352
353 ReleaseSysCache(tup);
354 }
355
356 /* handle finalfn, if supplied */
357 if (aggfinalfnName)
358 {
359 /*
360 * If finalfnExtraArgs is specified, the transfn takes the transtype
361 * plus all args; otherwise, it just takes the transtype plus any
362 * direct args. (Non-direct args are useless at runtime, and are
363 * actually passed as NULLs, but we may need them in the function
364 * signature to allow resolution of a polymorphic agg's result type.)
365 */
366 Oid ffnVariadicArgType = variadicArgType;
367
368 fnArgs[0] = aggTransType;
369 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
370 if (finalfnExtraArgs)
371 nargs_finalfn = numArgs + 1;
372 else
373 {
374 nargs_finalfn = numDirectArgs + 1;
375 if (numDirectArgs < numArgs)
376 {
377 /* variadic argument doesn't affect finalfn */
378 ffnVariadicArgType = InvalidOid;
379 }
380 }
381
382 finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
383 fnArgs, ffnVariadicArgType,
384 &finaltype);
385
386 /*
387 * When finalfnExtraArgs is specified, the finalfn will certainly be
388 * passed at least one null argument, so complain if it's strict.
389 * Nothing bad would happen at runtime (you'd just get a null result),
390 * but it's surely not what the user wants, so let's complain now.
391 */
392 if (finalfnExtraArgs && func_strict(finalfn))
393 ereport(ERROR,
394 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
395 errmsg("final function with extra arguments must not be declared STRICT")));
396 }
397 else
398 {
399 /*
400 * If no finalfn, aggregate result type is type of the state value
401 */
402 finaltype = aggTransType;
403 }
404 Assert(OidIsValid(finaltype));
405
406 /* handle the combinefn, if supplied */
407 if (aggcombinefnName)
408 {
409 Oid combineType;
410
411 /*
412 * Combine function must have 2 arguments, each of which is the trans
413 * type. VARIADIC doesn't affect it.
414 */
415 fnArgs[0] = aggTransType;
416 fnArgs[1] = aggTransType;
417
418 combinefn = lookup_agg_function(aggcombinefnName, 2,
419 fnArgs, InvalidOid,
420 &combineType);
421
422 /* Ensure the return type matches the aggregate's trans type */
423 if (combineType != aggTransType)
424 ereport(ERROR,
425 (errcode(ERRCODE_DATATYPE_MISMATCH),
426 errmsg("return type of combine function %s is not %s",
427 NameListToString(aggcombinefnName),
428 format_type_be(aggTransType))));
429
430 /*
431 * A combine function to combine INTERNAL states must accept nulls and
432 * ensure that the returned state is in the correct memory context. We
433 * cannot directly check the latter, but we can check the former.
434 */
435 if (aggTransType == INTERNALOID && func_strict(combinefn))
436 ereport(ERROR,
437 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
438 errmsg("combine function with transition type %s must not be declared STRICT",
439 format_type_be(aggTransType))));
440 }
441
442 /*
443 * Validate the serialization function, if present.
444 */
445 if (aggserialfnName)
446 {
447 /* signature is always serialize(internal) returns bytea */
448 fnArgs[0] = INTERNALOID;
449
450 serialfn = lookup_agg_function(aggserialfnName, 1,
451 fnArgs, InvalidOid,
452 &rettype);
453
454 if (rettype != BYTEAOID)
455 ereport(ERROR,
456 (errcode(ERRCODE_DATATYPE_MISMATCH),
457 errmsg("return type of serialization function %s is not %s",
458 NameListToString(aggserialfnName),
459 format_type_be(BYTEAOID))));
460 }
461
462 /*
463 * Validate the deserialization function, if present.
464 */
465 if (aggdeserialfnName)
466 {
467 /* signature is always deserialize(bytea, internal) returns internal */
468 fnArgs[0] = BYTEAOID;
469 fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
470
471 deserialfn = lookup_agg_function(aggdeserialfnName, 2,
472 fnArgs, InvalidOid,
473 &rettype);
474
475 if (rettype != INTERNALOID)
476 ereport(ERROR,
477 (errcode(ERRCODE_DATATYPE_MISMATCH),
478 errmsg("return type of deserialization function %s is not %s",
479 NameListToString(aggdeserialfnName),
480 format_type_be(INTERNALOID))));
481 }
482
483 /*
484 * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
485 * be polymorphic also, else parser will fail to deduce result type.
486 * (Note: given the previous test on transtype and inputs, this cannot
487 * happen, unless someone has snuck a finalfn definition into the catalogs
488 * that itself violates the rule against polymorphic result with no
489 * polymorphic input.)
490 */
491 detailmsg = check_valid_polymorphic_signature(finaltype,
492 aggArgTypes,
493 numArgs);
494 if (detailmsg)
495 ereport(ERROR,
496 (errcode(ERRCODE_DATATYPE_MISMATCH),
497 errmsg("cannot determine result data type"),
498 errdetail_internal("%s", detailmsg)));
499
500 /*
501 * Also, the return type can't be INTERNAL unless there's at least one
502 * INTERNAL argument. This is the same type-safety restriction we enforce
503 * for regular functions, but at the level of aggregates. We must test
504 * this explicitly because we allow INTERNAL as the transtype.
505 */
506 detailmsg = check_valid_internal_signature(finaltype,
507 aggArgTypes,
508 numArgs);
509 if (detailmsg)
510 ereport(ERROR,
511 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
512 errmsg("unsafe use of pseudo-type \"internal\""),
513 errdetail_internal("%s", detailmsg)));
514
515 /*
516 * If a moving-aggregate implementation is supplied, look up its finalfn
517 * if any, and check that the implied aggregate result type matches the
518 * plain implementation.
519 */
520 if (OidIsValid(aggmTransType))
521 {
522 /* handle finalfn, if supplied */
523 if (aggmfinalfnName)
524 {
525 /*
526 * The arguments are figured the same way as for the regular
527 * finalfn, but using aggmTransType and mfinalfnExtraArgs.
528 */
529 Oid ffnVariadicArgType = variadicArgType;
530
531 fnArgs[0] = aggmTransType;
532 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
533 if (mfinalfnExtraArgs)
534 nargs_finalfn = numArgs + 1;
535 else
536 {
537 nargs_finalfn = numDirectArgs + 1;
538 if (numDirectArgs < numArgs)
539 {
540 /* variadic argument doesn't affect finalfn */
541 ffnVariadicArgType = InvalidOid;
542 }
543 }
544
545 mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
546 fnArgs, ffnVariadicArgType,
547 &rettype);
548
549 /* As above, check strictness if mfinalfnExtraArgs is given */
550 if (mfinalfnExtraArgs && func_strict(mfinalfn))
551 ereport(ERROR,
552 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
553 errmsg("final function with extra arguments must not be declared STRICT")));
554 }
555 else
556 {
557 /*
558 * If no finalfn, aggregate result type is type of the state value
559 */
560 rettype = aggmTransType;
561 }
562 Assert(OidIsValid(rettype));
563 if (rettype != finaltype)
564 ereport(ERROR,
565 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
566 errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
567 format_type_be(rettype),
568 format_type_be(finaltype))));
569 }
570
571 /* handle sortop, if supplied */
572 if (aggsortopName)
573 {
574 if (numArgs != 1)
575 ereport(ERROR,
576 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
577 errmsg("sort operator can only be specified for single-argument aggregates")));
578 sortop = LookupOperName(NULL, aggsortopName,
579 aggArgTypes[0], aggArgTypes[0],
580 false, -1);
581 }
582
583 /*
584 * permission checks on used types
585 */
586 for (i = 0; i < numArgs; i++)
587 {
588 aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
589 if (aclresult != ACLCHECK_OK)
590 aclcheck_error_type(aclresult, aggArgTypes[i]);
591 }
592
593 aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
594 if (aclresult != ACLCHECK_OK)
595 aclcheck_error_type(aclresult, aggTransType);
596
597 if (OidIsValid(aggmTransType))
598 {
599 aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
600 if (aclresult != ACLCHECK_OK)
601 aclcheck_error_type(aclresult, aggmTransType);
602 }
603
604 aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
605 if (aclresult != ACLCHECK_OK)
606 aclcheck_error_type(aclresult, finaltype);
607
608
609 /*
610 * Everything looks okay. Try to create the pg_proc entry for the
611 * aggregate. (This could fail if there's already a conflicting entry.)
612 */
613
614 myself = ProcedureCreate(aggName,
615 aggNamespace,
616 replace, /* maybe replacement */
617 false, /* doesn't return a set */
618 finaltype, /* returnType */
619 GetUserId(), /* proowner */
620 INTERNALlanguageId, /* languageObjectId */
621 InvalidOid, /* no validator */
622 "aggregate_dummy", /* placeholder proc */
623 NULL, /* probin */
624 PROKIND_AGGREGATE,
625 false, /* security invoker (currently not
626 * definable for agg) */
627 false, /* isLeakProof */
628 false, /* isStrict (not needed for agg) */
629 PROVOLATILE_IMMUTABLE, /* volatility (not needed
630 * for agg) */
631 proparallel,
632 parameterTypes, /* paramTypes */
633 allParameterTypes, /* allParamTypes */
634 parameterModes, /* parameterModes */
635 parameterNames, /* parameterNames */
636 parameterDefaults, /* parameterDefaults */
637 PointerGetDatum(NULL), /* trftypes */
638 PointerGetDatum(NULL), /* proconfig */
639 InvalidOid, /* no prosupport */
640 1, /* procost */
641 0); /* prorows */
642 procOid = myself.objectId;
643
644 /*
645 * Okay to create the pg_aggregate entry.
646 */
647 aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
648 tupDesc = aggdesc->rd_att;
649
650 /* initialize nulls and values */
651 for (i = 0; i < Natts_pg_aggregate; i++)
652 {
653 nulls[i] = false;
654 values[i] = (Datum) NULL;
655 replaces[i] = true;
656 }
657 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
658 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
659 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
660 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
661 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
662 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
663 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
664 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
665 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
666 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
667 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
668 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
669 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
670 values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
671 values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
672 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
673 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
674 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
675 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
676 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
677 if (agginitval)
678 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
679 else
680 nulls[Anum_pg_aggregate_agginitval - 1] = true;
681 if (aggminitval)
682 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
683 else
684 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
685
686 if (replace)
687 oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
688 else
689 oldtup = NULL;
690
691 if (HeapTupleIsValid(oldtup))
692 {
693 Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
694
695 /*
696 * If we're replacing an existing entry, we need to validate that
697 * we're not changing anything that would break callers. Specifically
698 * we must not change aggkind or aggnumdirectargs, which affect how an
699 * aggregate call is treated in parse analysis.
700 */
701 if (aggKind != oldagg->aggkind)
702 ereport(ERROR,
703 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
704 errmsg("cannot change routine kind"),
705 (oldagg->aggkind == AGGKIND_NORMAL ?
706 errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
707 oldagg->aggkind == AGGKIND_ORDERED_SET ?
708 errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
709 oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
710 errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
711 0)));
712 if (numDirectArgs != oldagg->aggnumdirectargs)
713 ereport(ERROR,
714 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
715 errmsg("cannot change number of direct arguments of an aggregate function")));
716
717 replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
718 replaces[Anum_pg_aggregate_aggkind - 1] = false;
719 replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
720
721 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
722 CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
723 ReleaseSysCache(oldtup);
724 }
725 else
726 {
727 tup = heap_form_tuple(tupDesc, values, nulls);
728 CatalogTupleInsert(aggdesc, tup);
729 }
730
731 table_close(aggdesc, RowExclusiveLock);
732
733 /*
734 * Create dependencies for the aggregate (above and beyond those already
735 * made by ProcedureCreate). Note: we don't need an explicit dependency
736 * on aggTransType since we depend on it indirectly through transfn.
737 * Likewise for aggmTransType using the mtransfn, if it exists.
738 *
739 * If we're replacing an existing definition, ProcedureCreate deleted all
740 * our existing dependencies, so we have to do the same things here either
741 * way.
742 */
743
744 /* Depends on transition function */
745 referenced.classId = ProcedureRelationId;
746 referenced.objectId = transfn;
747 referenced.objectSubId = 0;
748 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
749
750 /* Depends on final function, if any */
751 if (OidIsValid(finalfn))
752 {
753 referenced.classId = ProcedureRelationId;
754 referenced.objectId = finalfn;
755 referenced.objectSubId = 0;
756 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
757 }
758
759 /* Depends on combine function, if any */
760 if (OidIsValid(combinefn))
761 {
762 referenced.classId = ProcedureRelationId;
763 referenced.objectId = combinefn;
764 referenced.objectSubId = 0;
765 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
766 }
767
768 /* Depends on serialization function, if any */
769 if (OidIsValid(serialfn))
770 {
771 referenced.classId = ProcedureRelationId;
772 referenced.objectId = serialfn;
773 referenced.objectSubId = 0;
774 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
775 }
776
777 /* Depends on deserialization function, if any */
778 if (OidIsValid(deserialfn))
779 {
780 referenced.classId = ProcedureRelationId;
781 referenced.objectId = deserialfn;
782 referenced.objectSubId = 0;
783 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
784 }
785
786 /* Depends on forward transition function, if any */
787 if (OidIsValid(mtransfn))
788 {
789 referenced.classId = ProcedureRelationId;
790 referenced.objectId = mtransfn;
791 referenced.objectSubId = 0;
792 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
793 }
794
795 /* Depends on inverse transition function, if any */
796 if (OidIsValid(minvtransfn))
797 {
798 referenced.classId = ProcedureRelationId;
799 referenced.objectId = minvtransfn;
800 referenced.objectSubId = 0;
801 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
802 }
803
804 /* Depends on final function, if any */
805 if (OidIsValid(mfinalfn))
806 {
807 referenced.classId = ProcedureRelationId;
808 referenced.objectId = mfinalfn;
809 referenced.objectSubId = 0;
810 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
811 }
812
813 /* Depends on sort operator, if any */
814 if (OidIsValid(sortop))
815 {
816 referenced.classId = OperatorRelationId;
817 referenced.objectId = sortop;
818 referenced.objectSubId = 0;
819 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
820 }
821
822 return myself;
823 }
824
825 /*
826 * lookup_agg_function
827 * common code for finding aggregate support functions
828 *
829 * fnName: possibly-schema-qualified function name
830 * nargs, input_types: expected function argument types
831 * variadicArgType: type of variadic argument if any, else InvalidOid
832 *
833 * Returns OID of function, and stores its return type into *rettype
834 *
835 * NB: must not scribble on input_types[], as we may re-use those
836 */
837 static Oid
lookup_agg_function(List * fnName,int nargs,Oid * input_types,Oid variadicArgType,Oid * rettype)838 lookup_agg_function(List *fnName,
839 int nargs,
840 Oid *input_types,
841 Oid variadicArgType,
842 Oid *rettype)
843 {
844 Oid fnOid;
845 bool retset;
846 int nvargs;
847 Oid vatype;
848 Oid *true_oid_array;
849 FuncDetailCode fdresult;
850 AclResult aclresult;
851 int i;
852
853 /*
854 * func_get_detail looks up the function in the catalogs, does
855 * disambiguation for polymorphic functions, handles inheritance, and
856 * returns the funcid and type and set or singleton status of the
857 * function's return value. it also returns the true argument types to
858 * the function.
859 */
860 fdresult = func_get_detail(fnName, NIL, NIL,
861 nargs, input_types, false, false,
862 &fnOid, rettype, &retset,
863 &nvargs, &vatype,
864 &true_oid_array, NULL);
865
866 /* only valid case is a normal function not returning a set */
867 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
868 ereport(ERROR,
869 (errcode(ERRCODE_UNDEFINED_FUNCTION),
870 errmsg("function %s does not exist",
871 func_signature_string(fnName, nargs,
872 NIL, input_types))));
873 if (retset)
874 ereport(ERROR,
875 (errcode(ERRCODE_DATATYPE_MISMATCH),
876 errmsg("function %s returns a set",
877 func_signature_string(fnName, nargs,
878 NIL, input_types))));
879
880 /*
881 * If the agg is declared to take VARIADIC ANY, the underlying functions
882 * had better be declared that way too, else they may receive too many
883 * parameters; but func_get_detail would have been happy with plain ANY.
884 * (Probably nothing very bad would happen, but it wouldn't work as the
885 * user expects.) Other combinations should work without any special
886 * pushups, given that we told func_get_detail not to expand VARIADIC.
887 */
888 if (variadicArgType == ANYOID && vatype != ANYOID)
889 ereport(ERROR,
890 (errcode(ERRCODE_DATATYPE_MISMATCH),
891 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
892 func_signature_string(fnName, nargs,
893 NIL, input_types))));
894
895 /*
896 * If there are any polymorphic types involved, enforce consistency, and
897 * possibly refine the result type. It's OK if the result is still
898 * polymorphic at this point, though.
899 */
900 *rettype = enforce_generic_type_consistency(input_types,
901 true_oid_array,
902 nargs,
903 *rettype,
904 true);
905
906 /*
907 * func_get_detail will find functions requiring run-time argument type
908 * coercion, but nodeAgg.c isn't prepared to deal with that
909 */
910 for (i = 0; i < nargs; i++)
911 {
912 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
913 ereport(ERROR,
914 (errcode(ERRCODE_DATATYPE_MISMATCH),
915 errmsg("function %s requires run-time type coercion",
916 func_signature_string(fnName, nargs,
917 NIL, true_oid_array))));
918 }
919
920 /* Check aggregate creator has permission to call the function */
921 aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
922 if (aclresult != ACLCHECK_OK)
923 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
924
925 return fnOid;
926 }
927