PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pg_aggregate.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_aggregate.c:

Go to the source code of this file.

Functions

static Oid lookup_agg_function (List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
 
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)
 

Function Documentation

◆ AggregateCreate()

ObjectAddress AggregateCreate ( const char *  aggName,
Oid  aggNamespace,
bool  replace,
char  aggKind,
int  numArgs,
int  numDirectArgs,
oidvector parameterTypes,
Datum  allParameterTypes,
Datum  parameterModes,
Datum  parameterNames,
List parameterDefaults,
Oid  variadicArgType,
List aggtransfnName,
List aggfinalfnName,
List aggcombinefnName,
List aggserialfnName,
List aggdeserialfnName,
List aggmtransfnName,
List aggminvtransfnName,
List aggmfinalfnName,
bool  finalfnExtraArgs,
bool  mfinalfnExtraArgs,
char  finalfnModify,
char  mfinalfnModify,
List aggsortopName,
Oid  aggTransType,
int32  aggTransSpace,
Oid  aggmTransType,
int32  aggmTransSpace,
const char *  agginitval,
const char *  aggminitval,
char  proparallel 
)

Definition at line 46 of file pg_aggregate.c.

78{
79 Relation aggdesc;
80 HeapTuple tup;
81 HeapTuple oldtup;
82 bool nulls[Natts_pg_aggregate];
83 Datum values[Natts_pg_aggregate];
84 bool replaces[Natts_pg_aggregate];
85 Form_pg_proc proc;
86 Oid transfn;
87 Oid finalfn = InvalidOid; /* can be omitted */
88 Oid combinefn = InvalidOid; /* can be omitted */
89 Oid serialfn = InvalidOid; /* can be omitted */
90 Oid deserialfn = InvalidOid; /* can be omitted */
91 Oid mtransfn = InvalidOid; /* can be omitted */
92 Oid minvtransfn = InvalidOid; /* can be omitted */
93 Oid mfinalfn = InvalidOid; /* can be omitted */
94 Oid sortop = InvalidOid; /* can be omitted */
95 Oid *aggArgTypes = parameterTypes->values;
96 bool mtransIsStrict = false;
97 Oid rettype;
98 Oid finaltype;
99 Oid fnArgs[FUNC_MAX_ARGS];
100 int nargs_transfn;
101 int nargs_finalfn;
102 Oid procOid;
103 TupleDesc tupDesc;
104 char *detailmsg;
105 int i;
106 ObjectAddress myself,
107 referenced;
108 ObjectAddresses *addrs;
109 AclResult aclresult;
110
111 /* sanity checks (caller should have caught these) */
112 if (!aggName)
113 elog(ERROR, "no aggregate name supplied");
114
115 if (!aggtransfnName)
116 elog(ERROR, "aggregate must have a transition function");
117
118 if (numDirectArgs < 0 || numDirectArgs > numArgs)
119 elog(ERROR, "incorrect number of direct arguments for aggregate");
120
121 /*
122 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
123 * and/or finalfn will be unrepresentable in pg_proc. We must check now
124 * to protect fixed-size arrays here and possibly in called functions.
125 */
126 if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
128 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
129 errmsg_plural("aggregates cannot have more than %d argument",
130 "aggregates cannot have more than %d arguments",
131 FUNC_MAX_ARGS - 1,
132 FUNC_MAX_ARGS - 1)));
133
134 /*
135 * If transtype is polymorphic, must have polymorphic argument also; else
136 * we will have no way to deduce the actual transtype.
137 */
138 detailmsg = check_valid_polymorphic_signature(aggTransType,
139 aggArgTypes,
140 numArgs);
141 if (detailmsg)
143 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
144 errmsg("cannot determine transition data type"),
145 errdetail_internal("%s", detailmsg)));
146
147 /*
148 * Likewise for moving-aggregate transtype, if any
149 */
150 if (OidIsValid(aggmTransType))
151 {
152 detailmsg = check_valid_polymorphic_signature(aggmTransType,
153 aggArgTypes,
154 numArgs);
155 if (detailmsg)
157 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158 errmsg("cannot determine transition data type"),
159 errdetail_internal("%s", detailmsg)));
160 }
161
162 /*
163 * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
164 * principle we could support regular variadic types, but it would make
165 * things much more complicated because we'd have to assemble the correct
166 * subsets of arguments into array values. Since no standard aggregates
167 * have use for such a case, we aren't bothering for now.
168 */
169 if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
170 variadicArgType != ANYOID)
172 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
173 errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
174
175 /*
176 * If it's a hypothetical-set aggregate, there must be at least as many
177 * direct arguments as aggregated ones, and the last N direct arguments
178 * must match the aggregated ones in type. (We have to check this again
179 * when the aggregate is called, in case ANY is involved, but it makes
180 * sense to reject the aggregate definition now if the declared arg types
181 * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
182 * indicating that the grammar merged identical VARIADIC entries from both
183 * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
184 * the aggregated side, which is not OK. Otherwise, insist on the last N
185 * parameter types on each side matching exactly.
186 */
187 if (aggKind == AGGKIND_HYPOTHETICAL &&
188 numDirectArgs < numArgs)
189 {
190 int numAggregatedArgs = numArgs - numDirectArgs;
191
192 if (OidIsValid(variadicArgType) ||
193 numDirectArgs < numAggregatedArgs ||
194 memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
195 aggArgTypes + numDirectArgs,
196 numAggregatedArgs * sizeof(Oid)) != 0)
198 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
199 errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
200 }
201
202 /*
203 * Find the transfn. For ordinary aggs, it takes the transtype plus all
204 * aggregate arguments. For ordered-set aggs, it takes the transtype plus
205 * all aggregated args, but not direct args. However, we have to treat
206 * specially the case where a trailing VARIADIC item is considered to
207 * cover both direct and aggregated args.
208 */
209 if (AGGKIND_IS_ORDERED_SET(aggKind))
210 {
211 if (numDirectArgs < numArgs)
212 nargs_transfn = numArgs - numDirectArgs + 1;
213 else
214 {
215 /* special case with VARIADIC last arg */
216 Assert(variadicArgType != InvalidOid);
217 nargs_transfn = 2;
218 }
219 fnArgs[0] = aggTransType;
220 memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
221 (nargs_transfn - 1) * sizeof(Oid));
222 }
223 else
224 {
225 nargs_transfn = numArgs + 1;
226 fnArgs[0] = aggTransType;
227 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
228 }
229 transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
230 fnArgs, variadicArgType,
231 &rettype);
232
233 /*
234 * Return type of transfn (possibly after refinement by
235 * enforce_generic_type_consistency, if transtype isn't polymorphic) must
236 * exactly match declared transtype.
237 *
238 * In the non-polymorphic-transtype case, it might be okay to allow a
239 * rettype that's binary-coercible to transtype, but I'm not quite
240 * convinced that it's either safe or useful. When transtype is
241 * polymorphic we *must* demand exact equality.
242 */
243 if (rettype != aggTransType)
245 (errcode(ERRCODE_DATATYPE_MISMATCH),
246 errmsg("return type of transition function %s is not %s",
247 NameListToString(aggtransfnName),
248 format_type_be(aggTransType))));
249
250 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
251 if (!HeapTupleIsValid(tup))
252 elog(ERROR, "cache lookup failed for function %u", transfn);
253 proc = (Form_pg_proc) GETSTRUCT(tup);
254
255 /*
256 * If the transfn is strict and the initval is NULL, make sure first input
257 * type and transtype are the same (or at least binary-compatible), so
258 * that it's OK to use the first input value as the initial transValue.
259 */
260 if (proc->proisstrict && agginitval == NULL)
261 {
262 if (numArgs < 1 ||
263 !IsBinaryCoercible(aggArgTypes[0], aggTransType))
265 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
266 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
267 }
268
269 ReleaseSysCache(tup);
270
271 /* handle moving-aggregate transfn, if supplied */
272 if (aggmtransfnName)
273 {
274 /*
275 * The arguments are the same as for the regular transfn, except that
276 * the transition data type might be different. So re-use the fnArgs
277 * values set up above, except for that one.
278 */
279 Assert(OidIsValid(aggmTransType));
280 fnArgs[0] = aggmTransType;
281
282 mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
283 fnArgs, variadicArgType,
284 &rettype);
285
286 /* As above, return type must exactly match declared mtranstype. */
287 if (rettype != aggmTransType)
289 (errcode(ERRCODE_DATATYPE_MISMATCH),
290 errmsg("return type of transition function %s is not %s",
291 NameListToString(aggmtransfnName),
292 format_type_be(aggmTransType))));
293
294 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
295 if (!HeapTupleIsValid(tup))
296 elog(ERROR, "cache lookup failed for function %u", mtransfn);
297 proc = (Form_pg_proc) GETSTRUCT(tup);
298
299 /*
300 * If the mtransfn is strict and the minitval is NULL, check first
301 * input type and mtranstype are binary-compatible.
302 */
303 if (proc->proisstrict && aggminitval == NULL)
304 {
305 if (numArgs < 1 ||
306 !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
308 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
309 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
310 }
311
312 /* Remember if mtransfn is strict; we may need this below */
313 mtransIsStrict = proc->proisstrict;
314
315 ReleaseSysCache(tup);
316 }
317
318 /* handle minvtransfn, if supplied */
319 if (aggminvtransfnName)
320 {
321 /*
322 * This must have the same number of arguments with the same types as
323 * the forward transition function, so just re-use the fnArgs data.
324 */
325 Assert(aggmtransfnName);
326
327 minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
328 fnArgs, variadicArgType,
329 &rettype);
330
331 /* As above, return type must exactly match declared mtranstype. */
332 if (rettype != aggmTransType)
334 (errcode(ERRCODE_DATATYPE_MISMATCH),
335 errmsg("return type of inverse transition function %s is not %s",
336 NameListToString(aggminvtransfnName),
337 format_type_be(aggmTransType))));
338
339 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
340 if (!HeapTupleIsValid(tup))
341 elog(ERROR, "cache lookup failed for function %u", minvtransfn);
342 proc = (Form_pg_proc) GETSTRUCT(tup);
343
344 /*
345 * We require the strictness settings of the forward and inverse
346 * transition functions to agree. This saves having to handle
347 * assorted special cases at execution time.
348 */
349 if (proc->proisstrict != mtransIsStrict)
351 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
352 errmsg("strictness of aggregate's forward and inverse transition functions must match")));
353
354 ReleaseSysCache(tup);
355 }
356
357 /* handle finalfn, if supplied */
358 if (aggfinalfnName)
359 {
360 /*
361 * If finalfnExtraArgs is specified, the transfn takes the transtype
362 * plus all args; otherwise, it just takes the transtype plus any
363 * direct args. (Non-direct args are useless at runtime, and are
364 * actually passed as NULLs, but we may need them in the function
365 * signature to allow resolution of a polymorphic agg's result type.)
366 */
367 Oid ffnVariadicArgType = variadicArgType;
368
369 fnArgs[0] = aggTransType;
370 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
371 if (finalfnExtraArgs)
372 nargs_finalfn = numArgs + 1;
373 else
374 {
375 nargs_finalfn = numDirectArgs + 1;
376 if (numDirectArgs < numArgs)
377 {
378 /* variadic argument doesn't affect finalfn */
379 ffnVariadicArgType = InvalidOid;
380 }
381 }
382
383 finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
384 fnArgs, ffnVariadicArgType,
385 &finaltype);
386
387 /*
388 * When finalfnExtraArgs is specified, the finalfn will certainly be
389 * passed at least one null argument, so complain if it's strict.
390 * Nothing bad would happen at runtime (you'd just get a null result),
391 * but it's surely not what the user wants, so let's complain now.
392 */
393 if (finalfnExtraArgs && func_strict(finalfn))
395 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
396 errmsg("final function with extra arguments must not be declared STRICT")));
397 }
398 else
399 {
400 /*
401 * If no finalfn, aggregate result type is type of the state value
402 */
403 finaltype = aggTransType;
404 }
405 Assert(OidIsValid(finaltype));
406
407 /* handle the combinefn, if supplied */
408 if (aggcombinefnName)
409 {
410 Oid combineType;
411
412 /*
413 * Combine function must have 2 arguments, each of which is the trans
414 * type. VARIADIC doesn't affect it.
415 */
416 fnArgs[0] = aggTransType;
417 fnArgs[1] = aggTransType;
418
419 combinefn = lookup_agg_function(aggcombinefnName, 2,
420 fnArgs, InvalidOid,
421 &combineType);
422
423 /* Ensure the return type matches the aggregate's trans type */
424 if (combineType != aggTransType)
426 (errcode(ERRCODE_DATATYPE_MISMATCH),
427 errmsg("return type of combine function %s is not %s",
428 NameListToString(aggcombinefnName),
429 format_type_be(aggTransType))));
430
431 /*
432 * A combine function to combine INTERNAL states must accept nulls and
433 * ensure that the returned state is in the correct memory context. We
434 * cannot directly check the latter, but we can check the former.
435 */
436 if (aggTransType == INTERNALOID && func_strict(combinefn))
438 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
439 errmsg("combine function with transition type %s must not be declared STRICT",
440 format_type_be(aggTransType))));
441 }
442
443 /*
444 * Validate the serialization function, if present.
445 */
446 if (aggserialfnName)
447 {
448 /* signature is always serialize(internal) returns bytea */
449 fnArgs[0] = INTERNALOID;
450
451 serialfn = lookup_agg_function(aggserialfnName, 1,
452 fnArgs, InvalidOid,
453 &rettype);
454
455 if (rettype != BYTEAOID)
457 (errcode(ERRCODE_DATATYPE_MISMATCH),
458 errmsg("return type of serialization function %s is not %s",
459 NameListToString(aggserialfnName),
460 format_type_be(BYTEAOID))));
461 }
462
463 /*
464 * Validate the deserialization function, if present.
465 */
466 if (aggdeserialfnName)
467 {
468 /* signature is always deserialize(bytea, internal) returns internal */
469 fnArgs[0] = BYTEAOID;
470 fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
471
472 deserialfn = lookup_agg_function(aggdeserialfnName, 2,
473 fnArgs, InvalidOid,
474 &rettype);
475
476 if (rettype != INTERNALOID)
478 (errcode(ERRCODE_DATATYPE_MISMATCH),
479 errmsg("return type of deserialization function %s is not %s",
480 NameListToString(aggdeserialfnName),
481 format_type_be(INTERNALOID))));
482 }
483
484 /*
485 * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
486 * be polymorphic also, else parser will fail to deduce result type.
487 * (Note: given the previous test on transtype and inputs, this cannot
488 * happen, unless someone has snuck a finalfn definition into the catalogs
489 * that itself violates the rule against polymorphic result with no
490 * polymorphic input.)
491 */
492 detailmsg = check_valid_polymorphic_signature(finaltype,
493 aggArgTypes,
494 numArgs);
495 if (detailmsg)
497 (errcode(ERRCODE_DATATYPE_MISMATCH),
498 errmsg("cannot determine result data type"),
499 errdetail_internal("%s", detailmsg)));
500
501 /*
502 * Also, the return type can't be INTERNAL unless there's at least one
503 * INTERNAL argument. This is the same type-safety restriction we enforce
504 * for regular functions, but at the level of aggregates. We must test
505 * this explicitly because we allow INTERNAL as the transtype.
506 */
507 detailmsg = check_valid_internal_signature(finaltype,
508 aggArgTypes,
509 numArgs);
510 if (detailmsg)
512 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
513 errmsg("unsafe use of pseudo-type \"internal\""),
514 errdetail_internal("%s", detailmsg)));
515
516 /*
517 * If a moving-aggregate implementation is supplied, look up its finalfn
518 * if any, and check that the implied aggregate result type matches the
519 * plain implementation.
520 */
521 if (OidIsValid(aggmTransType))
522 {
523 /* handle finalfn, if supplied */
524 if (aggmfinalfnName)
525 {
526 /*
527 * The arguments are figured the same way as for the regular
528 * finalfn, but using aggmTransType and mfinalfnExtraArgs.
529 */
530 Oid ffnVariadicArgType = variadicArgType;
531
532 fnArgs[0] = aggmTransType;
533 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
534 if (mfinalfnExtraArgs)
535 nargs_finalfn = numArgs + 1;
536 else
537 {
538 nargs_finalfn = numDirectArgs + 1;
539 if (numDirectArgs < numArgs)
540 {
541 /* variadic argument doesn't affect finalfn */
542 ffnVariadicArgType = InvalidOid;
543 }
544 }
545
546 mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
547 fnArgs, ffnVariadicArgType,
548 &rettype);
549
550 /* As above, check strictness if mfinalfnExtraArgs is given */
551 if (mfinalfnExtraArgs && func_strict(mfinalfn))
553 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
554 errmsg("final function with extra arguments must not be declared STRICT")));
555 }
556 else
557 {
558 /*
559 * If no finalfn, aggregate result type is type of the state value
560 */
561 rettype = aggmTransType;
562 }
563 Assert(OidIsValid(rettype));
564 if (rettype != finaltype)
566 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
567 errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
568 format_type_be(rettype),
569 format_type_be(finaltype))));
570 }
571
572 /* handle sortop, if supplied */
573 if (aggsortopName)
574 {
575 if (numArgs != 1)
577 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
578 errmsg("sort operator can only be specified for single-argument aggregates")));
579 sortop = LookupOperName(NULL, aggsortopName,
580 aggArgTypes[0], aggArgTypes[0],
581 false, -1);
582 }
583
584 /*
585 * permission checks on used types
586 */
587 for (i = 0; i < numArgs; i++)
588 {
589 aclresult = object_aclcheck(TypeRelationId, aggArgTypes[i], GetUserId(), ACL_USAGE);
590 if (aclresult != ACLCHECK_OK)
591 aclcheck_error_type(aclresult, aggArgTypes[i]);
592 }
593
594 aclresult = object_aclcheck(TypeRelationId, aggTransType, GetUserId(), ACL_USAGE);
595 if (aclresult != ACLCHECK_OK)
596 aclcheck_error_type(aclresult, aggTransType);
597
598 if (OidIsValid(aggmTransType))
599 {
600 aclresult = object_aclcheck(TypeRelationId, aggmTransType, GetUserId(), ACL_USAGE);
601 if (aclresult != ACLCHECK_OK)
602 aclcheck_error_type(aclresult, aggmTransType);
603 }
604
605 aclresult = object_aclcheck(TypeRelationId, finaltype, GetUserId(), ACL_USAGE);
606 if (aclresult != ACLCHECK_OK)
607 aclcheck_error_type(aclresult, finaltype);
608
609
610 /*
611 * Everything looks okay. Try to create the pg_proc entry for the
612 * aggregate. (This could fail if there's already a conflicting entry.)
613 */
614
615 myself = ProcedureCreate(aggName,
616 aggNamespace,
617 replace, /* maybe replacement */
618 false, /* doesn't return a set */
619 finaltype, /* returnType */
620 GetUserId(), /* proowner */
621 INTERNALlanguageId, /* languageObjectId */
622 InvalidOid, /* no validator */
623 "aggregate_dummy", /* placeholder (no such proc) */
624 NULL, /* probin */
625 NULL, /* prosqlbody */
626 PROKIND_AGGREGATE,
627 false, /* security invoker (currently not
628 * definable for agg) */
629 false, /* isLeakProof */
630 false, /* isStrict (not needed for agg) */
631 PROVOLATILE_IMMUTABLE, /* volatility (not needed
632 * for agg) */
633 proparallel,
634 parameterTypes, /* paramTypes */
635 allParameterTypes, /* allParamTypes */
636 parameterModes, /* parameterModes */
637 parameterNames, /* parameterNames */
638 parameterDefaults, /* parameterDefaults */
639 PointerGetDatum(NULL), /* trftypes */
640 NIL, /* trfoids */
641 PointerGetDatum(NULL), /* proconfig */
642 InvalidOid, /* no prosupport */
643 1, /* procost */
644 0); /* prorows */
645 procOid = myself.objectId;
646
647 /*
648 * Okay to create the pg_aggregate entry.
649 */
650 aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
651 tupDesc = aggdesc->rd_att;
652
653 /* initialize nulls and values */
654 for (i = 0; i < Natts_pg_aggregate; i++)
655 {
656 nulls[i] = false;
657 values[i] = (Datum) NULL;
658 replaces[i] = true;
659 }
660 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
661 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
662 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
663 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
664 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
665 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
666 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
667 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
668 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
669 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
670 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
671 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
672 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
673 values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
674 values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
675 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
676 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
677 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
678 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
679 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
680 if (agginitval)
681 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
682 else
683 nulls[Anum_pg_aggregate_agginitval - 1] = true;
684 if (aggminitval)
685 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
686 else
687 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
688
689 if (replace)
690 oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
691 else
692 oldtup = NULL;
693
694 if (HeapTupleIsValid(oldtup))
695 {
697
698 /*
699 * If we're replacing an existing entry, we need to validate that
700 * we're not changing anything that would break callers. Specifically
701 * we must not change aggkind or aggnumdirectargs, which affect how an
702 * aggregate call is treated in parse analysis.
703 */
704 if (aggKind != oldagg->aggkind)
706 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
707 errmsg("cannot change routine kind"),
708 (oldagg->aggkind == AGGKIND_NORMAL ?
709 errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
710 oldagg->aggkind == AGGKIND_ORDERED_SET ?
711 errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
712 oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
713 errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
714 0)));
715 if (numDirectArgs != oldagg->aggnumdirectargs)
717 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
718 errmsg("cannot change number of direct arguments of an aggregate function")));
719
720 replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
721 replaces[Anum_pg_aggregate_aggkind - 1] = false;
722 replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
723
724 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
725 CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
726 ReleaseSysCache(oldtup);
727 }
728 else
729 {
730 tup = heap_form_tuple(tupDesc, values, nulls);
731 CatalogTupleInsert(aggdesc, tup);
732 }
733
735
736 /*
737 * Create dependencies for the aggregate (above and beyond those already
738 * made by ProcedureCreate). Note: we don't need an explicit dependency
739 * on aggTransType since we depend on it indirectly through transfn.
740 * Likewise for aggmTransType using the mtransfn, if it exists.
741 *
742 * If we're replacing an existing definition, ProcedureCreate deleted all
743 * our existing dependencies, so we have to do the same things here either
744 * way.
745 */
746
747 addrs = new_object_addresses();
748
749 /* Depends on transition function */
750 ObjectAddressSet(referenced, ProcedureRelationId, transfn);
751 add_exact_object_address(&referenced, addrs);
752
753 /* Depends on final function, if any */
754 if (OidIsValid(finalfn))
755 {
756 ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
757 add_exact_object_address(&referenced, addrs);
758 }
759
760 /* Depends on combine function, if any */
761 if (OidIsValid(combinefn))
762 {
763 ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
764 add_exact_object_address(&referenced, addrs);
765 }
766
767 /* Depends on serialization function, if any */
768 if (OidIsValid(serialfn))
769 {
770 ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
771 add_exact_object_address(&referenced, addrs);
772 }
773
774 /* Depends on deserialization function, if any */
775 if (OidIsValid(deserialfn))
776 {
777 ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
778 add_exact_object_address(&referenced, addrs);
779 }
780
781 /* Depends on forward transition function, if any */
782 if (OidIsValid(mtransfn))
783 {
784 ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
785 add_exact_object_address(&referenced, addrs);
786 }
787
788 /* Depends on inverse transition function, if any */
789 if (OidIsValid(minvtransfn))
790 {
791 ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
792 add_exact_object_address(&referenced, addrs);
793 }
794
795 /* Depends on final function, if any */
796 if (OidIsValid(mfinalfn))
797 {
798 ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
799 add_exact_object_address(&referenced, addrs);
800 }
801
802 /* Depends on sort operator, if any */
803 if (OidIsValid(sortop))
804 {
805 ObjectAddressSet(referenced, OperatorRelationId, sortop);
806 add_exact_object_address(&referenced, addrs);
807 }
808
811 return myself;
812}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3821
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2958
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define OidIsValid(objectId)
Definition: c.h:746
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1181
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1231
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:77
#define RowExclusiveLock
Definition: lockdefs.h:38
bool func_strict(Oid funcid)
Definition: lsyscache.c:1901
Oid GetUserId(void)
Definition: miscinit.c:520
char * NameListToString(const List *names)
Definition: namespace.c:3594
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:99
#define ACL_USAGE
Definition: parsenodes.h:84
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:827
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
#define NIL
Definition: pg_list.h:68
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, List *trfoids, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:98
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
ItemPointerData t_self
Definition: htup.h:65
TupleDesc rd_att
Definition: rel.h:112
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:704
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, add_exact_object_address(), Assert(), BoolGetDatum(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), check_valid_internal_signature(), check_valid_polymorphic_signature(), CStringGetTextDatum, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errdetail_internal(), errmsg(), errmsg_plural(), ERROR, format_type_be(), free_object_addresses(), FUNC_MAX_ARGS, func_strict(), GETSTRUCT(), GetUserId(), heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, Int16GetDatum(), Int32GetDatum(), InvalidOid, IsBinaryCoercible(), lookup_agg_function(), LookupOperName(), NameListToString(), new_object_addresses(), NIL, object_aclcheck(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), ProcedureCreate(), RelationData::rd_att, record_object_address_dependencies(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), table_open(), oidvector::values, and values.

Referenced by DefineAggregate().

◆ lookup_agg_function()

static Oid lookup_agg_function ( List fnName,
int  nargs,
Oid input_types,
Oid  variadicArgType,
Oid rettype 
)
static

Definition at line 827 of file pg_aggregate.c.

832{
833 Oid fnOid;
834 bool retset;
835 int nvargs;
836 Oid vatype;
837 Oid *true_oid_array;
838 FuncDetailCode fdresult;
839 AclResult aclresult;
840 int i;
841
842 /*
843 * func_get_detail looks up the function in the catalogs, does
844 * disambiguation for polymorphic functions, handles inheritance, and
845 * returns the funcid and type and set or singleton status of the
846 * function's return value. it also returns the true argument types to
847 * the function.
848 */
849 fdresult = func_get_detail(fnName, NIL, NIL,
850 nargs, input_types, false, false, false,
851 &fnOid, rettype, &retset,
852 &nvargs, &vatype,
853 &true_oid_array, NULL);
854
855 /* only valid case is a normal function not returning a set */
856 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
858 (errcode(ERRCODE_UNDEFINED_FUNCTION),
859 errmsg("function %s does not exist",
860 func_signature_string(fnName, nargs,
861 NIL, input_types))));
862 if (retset)
864 (errcode(ERRCODE_DATATYPE_MISMATCH),
865 errmsg("function %s returns a set",
866 func_signature_string(fnName, nargs,
867 NIL, input_types))));
868
869 /*
870 * If the agg is declared to take VARIADIC ANY, the underlying functions
871 * had better be declared that way too, else they may receive too many
872 * parameters; but func_get_detail would have been happy with plain ANY.
873 * (Probably nothing very bad would happen, but it wouldn't work as the
874 * user expects.) Other combinations should work without any special
875 * pushups, given that we told func_get_detail not to expand VARIADIC.
876 */
877 if (variadicArgType == ANYOID && vatype != ANYOID)
879 (errcode(ERRCODE_DATATYPE_MISMATCH),
880 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
881 func_signature_string(fnName, nargs,
882 NIL, input_types))));
883
884 /*
885 * If there are any polymorphic types involved, enforce consistency, and
886 * possibly refine the result type. It's OK if the result is still
887 * polymorphic at this point, though.
888 */
889 *rettype = enforce_generic_type_consistency(input_types,
890 true_oid_array,
891 nargs,
892 *rettype,
893 true);
894
895 /*
896 * func_get_detail will find functions requiring run-time argument type
897 * coercion, but nodeAgg.c isn't prepared to deal with that
898 */
899 for (i = 0; i < nargs; i++)
900 {
901 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
903 (errcode(ERRCODE_DATATYPE_MISMATCH),
904 errmsg("function %s requires run-time type coercion",
905 func_signature_string(fnName, nargs,
906 NIL, true_oid_array))));
907 }
908
909 /* Check aggregate creator has permission to call the function */
910 aclresult = object_aclcheck(ProcedureRelationId, fnOid, GetUserId(), ACL_EXECUTE);
911 if (aclresult != ACLCHECK_OK)
912 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
913
914 return fnOid;
915}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2639
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1748
Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2030
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1395
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
@ OBJECT_FUNCTION
Definition: parsenodes.h:2336
#define ACL_EXECUTE
Definition: parsenodes.h:83

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, enforce_generic_type_consistency(), ereport, errcode(), errmsg(), ERROR, func_get_detail(), func_signature_string(), FUNCDETAIL_NORMAL, get_func_name(), GetUserId(), i, IsBinaryCoercible(), NIL, object_aclcheck(), OBJECT_FUNCTION, and OidIsValid.

Referenced by AggregateCreate().