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 PointerGetDatum(NULL), /* proconfig */
641 InvalidOid, /* no prosupport */
642 1, /* procost */
643 0); /* prorows */
644 procOid = myself.objectId;
645
646 /*
647 * Okay to create the pg_aggregate entry.
648 */
649 aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
650 tupDesc = aggdesc->rd_att;
651
652 /* initialize nulls and values */
653 for (i = 0; i < Natts_pg_aggregate; i++)
654 {
655 nulls[i] = false;
656 values[i] = (Datum) NULL;
657 replaces[i] = true;
658 }
659 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
660 values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
661 values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
662 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
663 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
664 values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
665 values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
666 values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
667 values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
668 values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
669 values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
670 values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
671 values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
672 values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
673 values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
674 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
675 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
676 values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
677 values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
678 values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
679 if (agginitval)
680 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
681 else
682 nulls[Anum_pg_aggregate_agginitval - 1] = true;
683 if (aggminitval)
684 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
685 else
686 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
687
688 if (replace)
689 oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
690 else
691 oldtup = NULL;
692
693 if (HeapTupleIsValid(oldtup))
694 {
696
697 /*
698 * If we're replacing an existing entry, we need to validate that
699 * we're not changing anything that would break callers. Specifically
700 * we must not change aggkind or aggnumdirectargs, which affect how an
701 * aggregate call is treated in parse analysis.
702 */
703 if (aggKind != oldagg->aggkind)
705 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
706 errmsg("cannot change routine kind"),
707 (oldagg->aggkind == AGGKIND_NORMAL ?
708 errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
709 oldagg->aggkind == AGGKIND_ORDERED_SET ?
710 errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
711 oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
712 errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
713 0)));
714 if (numDirectArgs != oldagg->aggnumdirectargs)
716 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
717 errmsg("cannot change number of direct arguments of an aggregate function")));
718
719 replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
720 replaces[Anum_pg_aggregate_aggkind - 1] = false;
721 replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
722
723 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
724 CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
725 ReleaseSysCache(oldtup);
726 }
727 else
728 {
729 tup = heap_form_tuple(tupDesc, values, nulls);
730 CatalogTupleInsert(aggdesc, tup);
731 }
732
734
735 /*
736 * Create dependencies for the aggregate (above and beyond those already
737 * made by ProcedureCreate). Note: we don't need an explicit dependency
738 * on aggTransType since we depend on it indirectly through transfn.
739 * Likewise for aggmTransType using the mtransfn, if it exists.
740 *
741 * If we're replacing an existing definition, ProcedureCreate deleted all
742 * our existing dependencies, so we have to do the same things here either
743 * way.
744 */
745
746 addrs = new_object_addresses();
747
748 /* Depends on transition function */
749 ObjectAddressSet(referenced, ProcedureRelationId, transfn);
750 add_exact_object_address(&referenced, addrs);
751
752 /* Depends on final function, if any */
753 if (OidIsValid(finalfn))
754 {
755 ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
756 add_exact_object_address(&referenced, addrs);
757 }
758
759 /* Depends on combine function, if any */
760 if (OidIsValid(combinefn))
761 {
762 ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
763 add_exact_object_address(&referenced, addrs);
764 }
765
766 /* Depends on serialization function, if any */
767 if (OidIsValid(serialfn))
768 {
769 ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
770 add_exact_object_address(&referenced, addrs);
771 }
772
773 /* Depends on deserialization function, if any */
774 if (OidIsValid(deserialfn))
775 {
776 ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
777 add_exact_object_address(&referenced, addrs);
778 }
779
780 /* Depends on forward transition function, if any */
781 if (OidIsValid(mtransfn))
782 {
783 ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
784 add_exact_object_address(&referenced, addrs);
785 }
786
787 /* Depends on inverse transition function, if any */
788 if (OidIsValid(minvtransfn))
789 {
790 ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
791 add_exact_object_address(&referenced, addrs);
792 }
793
794 /* Depends on final function, if any */
795 if (OidIsValid(mfinalfn))
796 {
797 ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
798 add_exact_object_address(&referenced, addrs);
799 }
800
801 /* Depends on sort operator, if any */
802 if (OidIsValid(sortop))
803 {
804 ObjectAddressSet(referenced, OperatorRelationId, sortop);
805 add_exact_object_address(&referenced, addrs);
806 }
807
810 return myself;
811}
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:3804
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2941
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define 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:1180
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
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:1844
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:826
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:70
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h: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(), 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 826 of file pg_aggregate.c.

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

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().