1 /*-------------------------------------------------------------------------
2 *
3 * pg_aggregate.c
4 * routines to support manipulation of the pg_aggregate relation
5 *
6 * Portions Copyright (c) 1996-2016, 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/heapam.h"
18 #include "access/htup_details.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_proc_fn.h"
26 #include "catalog/pg_type.h"
27 #include "miscadmin.h"
28 #include "parser/parse_coerce.h"
29 #include "parser/parse_func.h"
30 #include "parser/parse_oper.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/lsyscache.h"
34 #include "utils/rel.h"
35 #include "utils/syscache.h"
36
37
38 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
39 Oid variadicArgType,
40 Oid *rettype);
41
42
43 /*
44 * AggregateCreate
45 */
46 ObjectAddress
AggregateCreate(const char * aggName,Oid aggNamespace,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,List * aggsortopName,Oid aggTransType,int32 aggTransSpace,Oid aggmTransType,int32 aggmTransSpace,const char * agginitval,const char * aggminitval,char proparallel)47 AggregateCreate(const char *aggName,
48 Oid aggNamespace,
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 List *aggsortopName,
69 Oid aggTransType,
70 int32 aggTransSpace,
71 Oid aggmTransType,
72 int32 aggmTransSpace,
73 const char *agginitval,
74 const char *aggminitval,
75 char proparallel)
76 {
77 Relation aggdesc;
78 HeapTuple tup;
79 bool nulls[Natts_pg_aggregate];
80 Datum values[Natts_pg_aggregate];
81 Form_pg_proc proc;
82 Oid transfn;
83 Oid finalfn = InvalidOid; /* can be omitted */
84 Oid combinefn = InvalidOid; /* can be omitted */
85 Oid serialfn = InvalidOid; /* can be omitted */
86 Oid deserialfn = InvalidOid; /* can be omitted */
87 Oid mtransfn = InvalidOid; /* can be omitted */
88 Oid minvtransfn = InvalidOid; /* can be omitted */
89 Oid mfinalfn = InvalidOid; /* can be omitted */
90 Oid sortop = InvalidOid; /* can be omitted */
91 Oid *aggArgTypes = parameterTypes->values;
92 bool hasPolyArg;
93 bool hasInternalArg;
94 bool mtransIsStrict = false;
95 Oid rettype;
96 Oid finaltype;
97 Oid fnArgs[FUNC_MAX_ARGS];
98 int nargs_transfn;
99 int nargs_finalfn;
100 Oid procOid;
101 TupleDesc tupDesc;
102 int i;
103 ObjectAddress myself,
104 referenced;
105 AclResult aclresult;
106
107 /* sanity checks (caller should have caught these) */
108 if (!aggName)
109 elog(ERROR, "no aggregate name supplied");
110
111 if (!aggtransfnName)
112 elog(ERROR, "aggregate must have a transition function");
113
114 if (numDirectArgs < 0 || numDirectArgs > numArgs)
115 elog(ERROR, "incorrect number of direct args for aggregate");
116
117 /*
118 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
119 * and/or finalfn will be unrepresentable in pg_proc. We must check now
120 * to protect fixed-size arrays here and possibly in called functions.
121 */
122 if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
123 ereport(ERROR,
124 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
125 errmsg_plural("aggregates cannot have more than %d argument",
126 "aggregates cannot have more than %d arguments",
127 FUNC_MAX_ARGS - 1,
128 FUNC_MAX_ARGS - 1)));
129
130 /* check for polymorphic and INTERNAL arguments */
131 hasPolyArg = false;
132 hasInternalArg = false;
133 for (i = 0; i < numArgs; i++)
134 {
135 if (IsPolymorphicType(aggArgTypes[i]))
136 hasPolyArg = true;
137 else if (aggArgTypes[i] == INTERNALOID)
138 hasInternalArg = true;
139 }
140
141 /*
142 * If transtype is polymorphic, must have polymorphic argument also; else
143 * we will have no way to deduce the actual transtype.
144 */
145 if (IsPolymorphicType(aggTransType) && !hasPolyArg)
146 ereport(ERROR,
147 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
148 errmsg("cannot determine transition data type"),
149 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
150
151 /*
152 * Likewise for moving-aggregate transtype, if any
153 */
154 if (OidIsValid(aggmTransType) &&
155 IsPolymorphicType(aggmTransType) && !hasPolyArg)
156 ereport(ERROR,
157 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158 errmsg("cannot determine transition data type"),
159 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
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 if (IsPolymorphicType(finaltype) && !hasPolyArg)
492 ereport(ERROR,
493 (errcode(ERRCODE_DATATYPE_MISMATCH),
494 errmsg("cannot determine result data type"),
495 errdetail("An aggregate returning a polymorphic type "
496 "must have at least one polymorphic argument.")));
497
498 /*
499 * Also, the return type can't be INTERNAL unless there's at least one
500 * INTERNAL argument. This is the same type-safety restriction we enforce
501 * for regular functions, but at the level of aggregates. We must test
502 * this explicitly because we allow INTERNAL as the transtype.
503 */
504 if (finaltype == INTERNALOID && !hasInternalArg)
505 ereport(ERROR,
506 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
507 errmsg("unsafe use of pseudo-type \"internal\""),
508 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
509
510 /*
511 * If a moving-aggregate implementation is supplied, look up its finalfn
512 * if any, and check that the implied aggregate result type matches the
513 * plain implementation.
514 */
515 if (OidIsValid(aggmTransType))
516 {
517 /* handle finalfn, if supplied */
518 if (aggmfinalfnName)
519 {
520 /*
521 * The arguments are figured the same way as for the regular
522 * finalfn, but using aggmTransType and mfinalfnExtraArgs.
523 */
524 Oid ffnVariadicArgType = variadicArgType;
525
526 fnArgs[0] = aggmTransType;
527 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
528 if (mfinalfnExtraArgs)
529 nargs_finalfn = numArgs + 1;
530 else
531 {
532 nargs_finalfn = numDirectArgs + 1;
533 if (numDirectArgs < numArgs)
534 {
535 /* variadic argument doesn't affect finalfn */
536 ffnVariadicArgType = InvalidOid;
537 }
538 }
539
540 mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
541 fnArgs, ffnVariadicArgType,
542 &rettype);
543
544 /* As above, check strictness if mfinalfnExtraArgs is given */
545 if (mfinalfnExtraArgs && func_strict(mfinalfn))
546 ereport(ERROR,
547 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
548 errmsg("final function with extra arguments must not be declared STRICT")));
549 }
550 else
551 {
552 /*
553 * If no finalfn, aggregate result type is type of the state value
554 */
555 rettype = aggmTransType;
556 }
557 Assert(OidIsValid(rettype));
558 if (rettype != finaltype)
559 ereport(ERROR,
560 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
561 errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
562 format_type_be(rettype),
563 format_type_be(finaltype))));
564 }
565
566 /* handle sortop, if supplied */
567 if (aggsortopName)
568 {
569 if (numArgs != 1)
570 ereport(ERROR,
571 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572 errmsg("sort operator can only be specified for single-argument aggregates")));
573 sortop = LookupOperName(NULL, aggsortopName,
574 aggArgTypes[0], aggArgTypes[0],
575 false, -1);
576 }
577
578 /*
579 * permission checks on used types
580 */
581 for (i = 0; i < numArgs; i++)
582 {
583 aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
584 if (aclresult != ACLCHECK_OK)
585 aclcheck_error_type(aclresult, aggArgTypes[i]);
586 }
587
588 aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
589 if (aclresult != ACLCHECK_OK)
590 aclcheck_error_type(aclresult, aggTransType);
591
592 if (OidIsValid(aggmTransType))
593 {
594 aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
595 if (aclresult != ACLCHECK_OK)
596 aclcheck_error_type(aclresult, aggmTransType);
597 }
598
599 aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
600 if (aclresult != ACLCHECK_OK)
601 aclcheck_error_type(aclresult, finaltype);
602
603
604 /*
605 * Everything looks okay. Try to create the pg_proc entry for the
606 * aggregate. (This could fail if there's already a conflicting entry.)
607 */
608
609 myself = ProcedureCreate(aggName,
610 aggNamespace,
611 false, /* no replacement */
612 false, /* doesn't return a set */
613 finaltype, /* returnType */
614 GetUserId(), /* proowner */
615 INTERNALlanguageId, /* languageObjectId */
616 InvalidOid, /* no validator */
617 "aggregate_dummy", /* placeholder proc */
618 NULL, /* probin */
619 true, /* isAgg */
620 false, /* isWindowFunc */
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
626 * needed for agg) */
627 proparallel,
628 parameterTypes, /* paramTypes */
629 allParameterTypes, /* allParamTypes */
630 parameterModes, /* parameterModes */
631 parameterNames, /* parameterNames */
632 parameterDefaults, /* parameterDefaults */
633 PointerGetDatum(NULL), /* trftypes */
634 PointerGetDatum(NULL), /* proconfig */
635 1, /* procost */
636 0); /* prorows */
637 procOid = myself.objectId;
638
639 /*
640 * Okay to create the pg_aggregate entry.
641 */
642
643 /* initialize nulls and values */
644 for (i = 0; i < Natts_pg_aggregate; i++)
645 {
646 nulls[i] = false;
647 values[i] = (Datum) NULL;
648 }
649 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
650 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
651 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
652 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
653 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
654 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
655 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
656 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
657 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
658 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
659 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
660 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
661 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
662 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
663 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
664 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
665 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
666 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
667 if (agginitval)
668 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
669 else
670 nulls[Anum_pg_aggregate_agginitval - 1] = true;
671 if (aggminitval)
672 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
673 else
674 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
675
676 aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
677 tupDesc = aggdesc->rd_att;
678
679 tup = heap_form_tuple(tupDesc, values, nulls);
680 simple_heap_insert(aggdesc, tup);
681
682 CatalogUpdateIndexes(aggdesc, tup);
683
684 heap_close(aggdesc, RowExclusiveLock);
685
686 /*
687 * Create dependencies for the aggregate (above and beyond those already
688 * made by ProcedureCreate). Note: we don't need an explicit dependency
689 * on aggTransType since we depend on it indirectly through transfn.
690 * Likewise for aggmTransType using the mtransfunc, if it exists.
691 */
692
693 /* Depends on transition function */
694 referenced.classId = ProcedureRelationId;
695 referenced.objectId = transfn;
696 referenced.objectSubId = 0;
697 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
698
699 /* Depends on final function, if any */
700 if (OidIsValid(finalfn))
701 {
702 referenced.classId = ProcedureRelationId;
703 referenced.objectId = finalfn;
704 referenced.objectSubId = 0;
705 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
706 }
707
708 /* Depends on combine function, if any */
709 if (OidIsValid(combinefn))
710 {
711 referenced.classId = ProcedureRelationId;
712 referenced.objectId = combinefn;
713 referenced.objectSubId = 0;
714 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
715 }
716
717 /* Depends on serialization function, if any */
718 if (OidIsValid(serialfn))
719 {
720 referenced.classId = ProcedureRelationId;
721 referenced.objectId = serialfn;
722 referenced.objectSubId = 0;
723 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
724 }
725
726 /* Depends on deserialization function, if any */
727 if (OidIsValid(deserialfn))
728 {
729 referenced.classId = ProcedureRelationId;
730 referenced.objectId = deserialfn;
731 referenced.objectSubId = 0;
732 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
733 }
734
735 /* Depends on forward transition function, if any */
736 if (OidIsValid(mtransfn))
737 {
738 referenced.classId = ProcedureRelationId;
739 referenced.objectId = mtransfn;
740 referenced.objectSubId = 0;
741 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
742 }
743
744 /* Depends on inverse transition function, if any */
745 if (OidIsValid(minvtransfn))
746 {
747 referenced.classId = ProcedureRelationId;
748 referenced.objectId = minvtransfn;
749 referenced.objectSubId = 0;
750 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
751 }
752
753 /* Depends on final function, if any */
754 if (OidIsValid(mfinalfn))
755 {
756 referenced.classId = ProcedureRelationId;
757 referenced.objectId = mfinalfn;
758 referenced.objectSubId = 0;
759 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
760 }
761
762 /* Depends on sort operator, if any */
763 if (OidIsValid(sortop))
764 {
765 referenced.classId = OperatorRelationId;
766 referenced.objectId = sortop;
767 referenced.objectSubId = 0;
768 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
769 }
770
771 return myself;
772 }
773
774 /*
775 * lookup_agg_function
776 * common code for finding aggregate support functions
777 *
778 * fnName: possibly-schema-qualified function name
779 * nargs, input_types: expected function argument types
780 * variadicArgType: type of variadic argument if any, else InvalidOid
781 *
782 * Returns OID of function, and stores its return type into *rettype
783 *
784 * NB: must not scribble on input_types[], as we may re-use those
785 */
786 static Oid
lookup_agg_function(List * fnName,int nargs,Oid * input_types,Oid variadicArgType,Oid * rettype)787 lookup_agg_function(List *fnName,
788 int nargs,
789 Oid *input_types,
790 Oid variadicArgType,
791 Oid *rettype)
792 {
793 Oid fnOid;
794 bool retset;
795 int nvargs;
796 Oid vatype;
797 Oid *true_oid_array;
798 FuncDetailCode fdresult;
799 AclResult aclresult;
800 int i;
801
802 /*
803 * func_get_detail looks up the function in the catalogs, does
804 * disambiguation for polymorphic functions, handles inheritance, and
805 * returns the funcid and type and set or singleton status of the
806 * function's return value. it also returns the true argument types to
807 * the function.
808 */
809 fdresult = func_get_detail(fnName, NIL, NIL,
810 nargs, input_types, false, false,
811 &fnOid, rettype, &retset,
812 &nvargs, &vatype,
813 &true_oid_array, NULL);
814
815 /* only valid case is a normal function not returning a set */
816 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
817 ereport(ERROR,
818 (errcode(ERRCODE_UNDEFINED_FUNCTION),
819 errmsg("function %s does not exist",
820 func_signature_string(fnName, nargs,
821 NIL, input_types))));
822 if (retset)
823 ereport(ERROR,
824 (errcode(ERRCODE_DATATYPE_MISMATCH),
825 errmsg("function %s returns a set",
826 func_signature_string(fnName, nargs,
827 NIL, input_types))));
828
829 /*
830 * If the agg is declared to take VARIADIC ANY, the underlying functions
831 * had better be declared that way too, else they may receive too many
832 * parameters; but func_get_detail would have been happy with plain ANY.
833 * (Probably nothing very bad would happen, but it wouldn't work as the
834 * user expects.) Other combinations should work without any special
835 * pushups, given that we told func_get_detail not to expand VARIADIC.
836 */
837 if (variadicArgType == ANYOID && vatype != ANYOID)
838 ereport(ERROR,
839 (errcode(ERRCODE_DATATYPE_MISMATCH),
840 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
841 func_signature_string(fnName, nargs,
842 NIL, input_types))));
843
844 /*
845 * If there are any polymorphic types involved, enforce consistency, and
846 * possibly refine the result type. It's OK if the result is still
847 * polymorphic at this point, though.
848 */
849 *rettype = enforce_generic_type_consistency(input_types,
850 true_oid_array,
851 nargs,
852 *rettype,
853 true);
854
855 /*
856 * func_get_detail will find functions requiring run-time argument type
857 * coercion, but nodeAgg.c isn't prepared to deal with that
858 */
859 for (i = 0; i < nargs; i++)
860 {
861 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
862 ereport(ERROR,
863 (errcode(ERRCODE_DATATYPE_MISMATCH),
864 errmsg("function %s requires run-time type coercion",
865 func_signature_string(fnName, nargs,
866 NIL, true_oid_array))));
867 }
868
869 /* Check aggregate creator has permission to call the function */
870 aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
871 if (aclresult != ACLCHECK_OK)
872 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(fnOid));
873
874 return fnOid;
875 }
876