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