PostgreSQL Source Code  git master
pg_aggregate.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_aggregate.c
4  * routines to support manipulation of the pg_aggregate relation
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/pg_aggregate.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "access/table.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_aggregate.h"
22 #include "catalog/pg_language.h"
23 #include "catalog/pg_operator.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "parser/parse_coerce.h"
28 #include "parser/parse_func.h"
29 #include "parser/parse_oper.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
35 
36 
37 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
38  Oid variadicArgType,
39  Oid *rettype);
40 
41 
42 /*
43  * AggregateCreate
44  */
46 AggregateCreate(const char *aggName,
47  Oid aggNamespace,
48  bool replace,
49  char aggKind,
50  int numArgs,
51  int numDirectArgs,
52  oidvector *parameterTypes,
53  Datum allParameterTypes,
54  Datum parameterModes,
55  Datum parameterNames,
56  List *parameterDefaults,
57  Oid variadicArgType,
58  List *aggtransfnName,
59  List *aggfinalfnName,
60  List *aggcombinefnName,
61  List *aggserialfnName,
62  List *aggdeserialfnName,
63  List *aggmtransfnName,
64  List *aggminvtransfnName,
65  List *aggmfinalfnName,
66  bool finalfnExtraArgs,
67  bool mfinalfnExtraArgs,
68  char finalfnModify,
69  char mfinalfnModify,
70  List *aggsortopName,
71  Oid aggTransType,
72  int32 aggTransSpace,
73  Oid aggmTransType,
74  int32 aggmTransSpace,
75  const char *agginitval,
76  const char *aggminitval,
77  char proparallel)
78 {
79  Relation aggdesc;
80  HeapTuple tup;
81  HeapTuple oldtup;
82  bool nulls[Natts_pg_aggregate];
83  Datum values[Natts_pg_aggregate];
84  bool replaces[Natts_pg_aggregate];
85  Form_pg_proc proc;
86  Oid transfn;
87  Oid finalfn = InvalidOid; /* can be omitted */
88  Oid combinefn = InvalidOid; /* can be omitted */
89  Oid serialfn = InvalidOid; /* can be omitted */
90  Oid deserialfn = InvalidOid; /* can be omitted */
91  Oid mtransfn = InvalidOid; /* can be omitted */
92  Oid minvtransfn = InvalidOid; /* can be omitted */
93  Oid mfinalfn = InvalidOid; /* can be omitted */
94  Oid sortop = InvalidOid; /* can be omitted */
95  Oid *aggArgTypes = parameterTypes->values;
96  bool mtransIsStrict = false;
97  Oid rettype;
98  Oid finaltype;
99  Oid fnArgs[FUNC_MAX_ARGS];
100  int nargs_transfn;
101  int nargs_finalfn;
102  Oid procOid;
103  TupleDesc tupDesc;
104  char *detailmsg;
105  int i;
106  ObjectAddress myself,
107  referenced;
108  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)
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  /*
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)
142  ereport(ERROR,
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)
156  ereport(ERROR,
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)
171  ereport(ERROR,
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)
197  ereport(ERROR,
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)
244  ereport(ERROR,
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))
264  ereport(ERROR,
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)
288  ereport(ERROR,
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))
307  ereport(ERROR,
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)
333  ereport(ERROR,
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)
350  ereport(ERROR,
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))
394  ereport(ERROR,
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)
425  ereport(ERROR,
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))
437  ereport(ERROR,
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)
456  ereport(ERROR,
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)
477  ereport(ERROR,
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)
496  ereport(ERROR,
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)
511  ereport(ERROR,
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))
552  ereport(ERROR,
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)
565  ereport(ERROR,
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)
576  ereport(ERROR,
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  {
695  Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
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)
704  ereport(ERROR,
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)
715  ereport(ERROR,
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 
733  table_close(aggdesc, RowExclusiveLock);
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 
809  free_object_addresses(addrs);
810  return myself;
811 }
812 
813 /*
814  * lookup_agg_function
815  * common code for finding aggregate support functions
816  *
817  * fnName: possibly-schema-qualified function name
818  * nargs, input_types: expected function argument types
819  * variadicArgType: type of variadic argument if any, else InvalidOid
820  *
821  * Returns OID of function, and stores its return type into *rettype
822  *
823  * NB: must not scribble on input_types[], as we may re-use those
824  */
825 static Oid
827  int nargs,
828  Oid *input_types,
829  Oid variadicArgType,
830  Oid *rettype)
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))
856  ereport(ERROR,
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)
862  ereport(ERROR,
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)
877  ereport(ERROR,
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]))
901  ereport(ERROR,
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 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2688
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3876
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3007
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2740
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1182
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1232
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
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:73
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
bool func_strict(Oid funcid)
Definition: lsyscache.c:1761
Oid GetUserId(void)
Definition: miscinit.c:514
char * NameListToString(const List *names)
Definition: namespace.c:3579
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
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:1394
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2029
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
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
@ OBJECT_FUNCTION
Definition: parsenodes.h:2282
#define ACL_EXECUTE
Definition: parsenodes.h:83
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: pg_aggregate.c:46
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
#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, 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:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40