PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/pg_aggregate.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/heapam.h"
18 #include "access/htup_details.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_aggregate.h"
22 #include "catalog/pg_language.h"
23 #include "catalog/pg_operator.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_proc_fn.h"
26 #include "catalog/pg_type.h"
27 #include "miscadmin.h"
28 #include "parser/parse_coerce.h"
29 #include "parser/parse_func.h"
30 #include "parser/parse_oper.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/lsyscache.h"
34 #include "utils/rel.h"
35 #include "utils/syscache.h"
36 
37 
38 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
39  Oid variadicArgType,
40  Oid *rettype);
41 
42 
43 /*
44  * AggregateCreate
45  */
47 AggregateCreate(const char *aggName,
48  Oid aggNamespace,
49  char aggKind,
50  int numArgs,
51  int numDirectArgs,
52  oidvector *parameterTypes,
53  Datum allParameterTypes,
54  Datum parameterModes,
55  Datum parameterNames,
56  List *parameterDefaults,
57  Oid variadicArgType,
58  List *aggtransfnName,
59  List *aggfinalfnName,
60  List *aggcombinefnName,
61  List *aggserialfnName,
62  List *aggdeserialfnName,
63  List *aggmtransfnName,
64  List *aggminvtransfnName,
65  List *aggmfinalfnName,
66  bool finalfnExtraArgs,
67  bool mfinalfnExtraArgs,
68  List *aggsortopName,
69  Oid aggTransType,
70  int32 aggTransSpace,
71  Oid aggmTransType,
72  int32 aggmTransSpace,
73  const char *agginitval,
74  const char *aggminitval,
75  char proparallel)
76 {
77  Relation aggdesc;
78  HeapTuple tup;
79  bool nulls[Natts_pg_aggregate];
81  Form_pg_proc proc;
82  Oid transfn;
83  Oid finalfn = InvalidOid; /* can be omitted */
84  Oid combinefn = InvalidOid; /* can be omitted */
85  Oid serialfn = InvalidOid; /* can be omitted */
86  Oid deserialfn = InvalidOid; /* can be omitted */
87  Oid mtransfn = InvalidOid; /* can be omitted */
88  Oid minvtransfn = InvalidOid; /* can be omitted */
89  Oid mfinalfn = InvalidOid; /* can be omitted */
90  Oid sortop = InvalidOid; /* can be omitted */
91  Oid *aggArgTypes = parameterTypes->values;
92  bool hasPolyArg;
93  bool hasInternalArg;
94  bool mtransIsStrict = false;
95  Oid rettype;
96  Oid finaltype;
97  Oid fnArgs[FUNC_MAX_ARGS];
98  int nargs_transfn;
99  int nargs_finalfn;
100  Oid procOid;
101  TupleDesc tupDesc;
102  int i;
103  ObjectAddress myself,
104  referenced;
105  AclResult aclresult;
106 
107  /* sanity checks (caller should have caught these) */
108  if (!aggName)
109  elog(ERROR, "no aggregate name supplied");
110 
111  if (!aggtransfnName)
112  elog(ERROR, "aggregate must have a transition function");
113 
114  if (numDirectArgs < 0 || numDirectArgs > numArgs)
115  elog(ERROR, "incorrect number of direct args for aggregate");
116 
117  /*
118  * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
119  * and/or finalfn will be unrepresentable in pg_proc. We must check now
120  * to protect fixed-size arrays here and possibly in called functions.
121  */
122  if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
123  ereport(ERROR,
124  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
125  errmsg_plural("aggregates cannot have more than %d argument",
126  "aggregates cannot have more than %d arguments",
127  FUNC_MAX_ARGS - 1,
128  FUNC_MAX_ARGS - 1)));
129 
130  /* check for polymorphic and INTERNAL arguments */
131  hasPolyArg = false;
132  hasInternalArg = false;
133  for (i = 0; i < numArgs; i++)
134  {
135  if (IsPolymorphicType(aggArgTypes[i]))
136  hasPolyArg = true;
137  else if (aggArgTypes[i] == INTERNALOID)
138  hasInternalArg = true;
139  }
140 
141  /*
142  * If transtype is polymorphic, must have polymorphic argument also; else
143  * we will have no way to deduce the actual transtype.
144  */
145  if (IsPolymorphicType(aggTransType) && !hasPolyArg)
146  ereport(ERROR,
147  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
148  errmsg("cannot determine transition data type"),
149  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
150 
151  /*
152  * Likewise for moving-aggregate transtype, if any
153  */
154  if (OidIsValid(aggmTransType) &&
155  IsPolymorphicType(aggmTransType) && !hasPolyArg)
156  ereport(ERROR,
157  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158  errmsg("cannot determine transition data type"),
159  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
160 
161  /*
162  * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
163  * principle we could support regular variadic types, but it would make
164  * things much more complicated because we'd have to assemble the correct
165  * subsets of arguments into array values. Since no standard aggregates
166  * have use for such a case, we aren't bothering for now.
167  */
168  if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
169  variadicArgType != ANYOID)
170  ereport(ERROR,
171  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
172  errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
173 
174  /*
175  * If it's a hypothetical-set aggregate, there must be at least as many
176  * direct arguments as aggregated ones, and the last N direct arguments
177  * must match the aggregated ones in type. (We have to check this again
178  * when the aggregate is called, in case ANY is involved, but it makes
179  * sense to reject the aggregate definition now if the declared arg types
180  * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
181  * indicating that the grammar merged identical VARIADIC entries from both
182  * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
183  * the aggregated side, which is not OK. Otherwise, insist on the last N
184  * parameter types on each side matching exactly.
185  */
186  if (aggKind == AGGKIND_HYPOTHETICAL &&
187  numDirectArgs < numArgs)
188  {
189  int numAggregatedArgs = numArgs - numDirectArgs;
190 
191  if (OidIsValid(variadicArgType) ||
192  numDirectArgs < numAggregatedArgs ||
193  memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
194  aggArgTypes + numDirectArgs,
195  numAggregatedArgs * sizeof(Oid)) != 0)
196  ereport(ERROR,
197  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
198  errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
199  }
200 
201  /*
202  * Find the transfn. For ordinary aggs, it takes the transtype plus all
203  * aggregate arguments. For ordered-set aggs, it takes the transtype plus
204  * all aggregated args, but not direct args. However, we have to treat
205  * specially the case where a trailing VARIADIC item is considered to
206  * cover both direct and aggregated args.
207  */
208  if (AGGKIND_IS_ORDERED_SET(aggKind))
209  {
210  if (numDirectArgs < numArgs)
211  nargs_transfn = numArgs - numDirectArgs + 1;
212  else
213  {
214  /* special case with VARIADIC last arg */
215  Assert(variadicArgType != InvalidOid);
216  nargs_transfn = 2;
217  }
218  fnArgs[0] = aggTransType;
219  memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
220  (nargs_transfn - 1) * sizeof(Oid));
221  }
222  else
223  {
224  nargs_transfn = numArgs + 1;
225  fnArgs[0] = aggTransType;
226  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
227  }
228  transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
229  fnArgs, variadicArgType,
230  &rettype);
231 
232  /*
233  * Return type of transfn (possibly after refinement by
234  * enforce_generic_type_consistency, if transtype isn't polymorphic) must
235  * exactly match declared transtype.
236  *
237  * In the non-polymorphic-transtype case, it might be okay to allow a
238  * rettype that's binary-coercible to transtype, but I'm not quite
239  * convinced that it's either safe or useful. When transtype is
240  * polymorphic we *must* demand exact equality.
241  */
242  if (rettype != aggTransType)
243  ereport(ERROR,
244  (errcode(ERRCODE_DATATYPE_MISMATCH),
245  errmsg("return type of transition function %s is not %s",
246  NameListToString(aggtransfnName),
247  format_type_be(aggTransType))));
248 
249  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
250  if (!HeapTupleIsValid(tup))
251  elog(ERROR, "cache lookup failed for function %u", transfn);
252  proc = (Form_pg_proc) GETSTRUCT(tup);
253 
254  /*
255  * If the transfn is strict and the initval is NULL, make sure first input
256  * type and transtype are the same (or at least binary-compatible), so
257  * that it's OK to use the first input value as the initial transValue.
258  */
259  if (proc->proisstrict && agginitval == NULL)
260  {
261  if (numArgs < 1 ||
262  !IsBinaryCoercible(aggArgTypes[0], aggTransType))
263  ereport(ERROR,
264  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
265  errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
266  }
267 
268  ReleaseSysCache(tup);
269 
270  /* handle moving-aggregate transfn, if supplied */
271  if (aggmtransfnName)
272  {
273  /*
274  * The arguments are the same as for the regular transfn, except that
275  * the transition data type might be different. So re-use the fnArgs
276  * values set up above, except for that one.
277  */
278  Assert(OidIsValid(aggmTransType));
279  fnArgs[0] = aggmTransType;
280 
281  mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
282  fnArgs, variadicArgType,
283  &rettype);
284 
285  /* As above, return type must exactly match declared mtranstype. */
286  if (rettype != aggmTransType)
287  ereport(ERROR,
288  (errcode(ERRCODE_DATATYPE_MISMATCH),
289  errmsg("return type of transition function %s is not %s",
290  NameListToString(aggmtransfnName),
291  format_type_be(aggmTransType))));
292 
293  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
294  if (!HeapTupleIsValid(tup))
295  elog(ERROR, "cache lookup failed for function %u", mtransfn);
296  proc = (Form_pg_proc) GETSTRUCT(tup);
297 
298  /*
299  * If the mtransfn is strict and the minitval is NULL, check first
300  * input type and mtranstype are binary-compatible.
301  */
302  if (proc->proisstrict && aggminitval == NULL)
303  {
304  if (numArgs < 1 ||
305  !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
306  ereport(ERROR,
307  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
308  errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
309  }
310 
311  /* Remember if mtransfn is strict; we may need this below */
312  mtransIsStrict = proc->proisstrict;
313 
314  ReleaseSysCache(tup);
315  }
316 
317  /* handle minvtransfn, if supplied */
318  if (aggminvtransfnName)
319  {
320  /*
321  * This must have the same number of arguments with the same types as
322  * the forward transition function, so just re-use the fnArgs data.
323  */
324  Assert(aggmtransfnName);
325 
326  minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
327  fnArgs, variadicArgType,
328  &rettype);
329 
330  /* As above, return type must exactly match declared mtranstype. */
331  if (rettype != aggmTransType)
332  ereport(ERROR,
333  (errcode(ERRCODE_DATATYPE_MISMATCH),
334  errmsg("return type of inverse transition function %s is not %s",
335  NameListToString(aggminvtransfnName),
336  format_type_be(aggmTransType))));
337 
338  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
339  if (!HeapTupleIsValid(tup))
340  elog(ERROR, "cache lookup failed for function %u", minvtransfn);
341  proc = (Form_pg_proc) GETSTRUCT(tup);
342 
343  /*
344  * We require the strictness settings of the forward and inverse
345  * transition functions to agree. This saves having to handle
346  * assorted special cases at execution time.
347  */
348  if (proc->proisstrict != mtransIsStrict)
349  ereport(ERROR,
350  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351  errmsg("strictness of aggregate's forward and inverse transition functions must match")));
352 
353  ReleaseSysCache(tup);
354  }
355 
356  /* handle finalfn, if supplied */
357  if (aggfinalfnName)
358  {
359  /*
360  * If finalfnExtraArgs is specified, the transfn takes the transtype
361  * plus all args; otherwise, it just takes the transtype plus any
362  * direct args. (Non-direct args are useless at runtime, and are
363  * actually passed as NULLs, but we may need them in the function
364  * signature to allow resolution of a polymorphic agg's result type.)
365  */
366  Oid ffnVariadicArgType = variadicArgType;
367 
368  fnArgs[0] = aggTransType;
369  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
370  if (finalfnExtraArgs)
371  nargs_finalfn = numArgs + 1;
372  else
373  {
374  nargs_finalfn = numDirectArgs + 1;
375  if (numDirectArgs < numArgs)
376  {
377  /* variadic argument doesn't affect finalfn */
378  ffnVariadicArgType = InvalidOid;
379  }
380  }
381 
382  finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
383  fnArgs, ffnVariadicArgType,
384  &finaltype);
385 
386  /*
387  * When finalfnExtraArgs is specified, the finalfn will certainly be
388  * passed at least one null argument, so complain if it's strict.
389  * Nothing bad would happen at runtime (you'd just get a null result),
390  * but it's surely not what the user wants, so let's complain now.
391  */
392  if (finalfnExtraArgs && func_strict(finalfn))
393  ereport(ERROR,
394  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
395  errmsg("final function with extra arguments must not be declared STRICT")));
396  }
397  else
398  {
399  /*
400  * If no finalfn, aggregate result type is type of the state value
401  */
402  finaltype = aggTransType;
403  }
404  Assert(OidIsValid(finaltype));
405 
406  /* handle the combinefn, if supplied */
407  if (aggcombinefnName)
408  {
409  Oid combineType;
410 
411  /*
412  * Combine function must have 2 argument, each of which is the trans
413  * type
414  */
415  fnArgs[0] = aggTransType;
416  fnArgs[1] = aggTransType;
417 
418  combinefn = lookup_agg_function(aggcombinefnName, 2, fnArgs,
419  variadicArgType, &combineType);
420 
421  /* Ensure the return type matches the aggregates trans type */
422  if (combineType != aggTransType)
423  ereport(ERROR,
424  (errcode(ERRCODE_DATATYPE_MISMATCH),
425  errmsg("return type of combine function %s is not %s",
426  NameListToString(aggcombinefnName),
427  format_type_be(aggTransType))));
428 
429  /*
430  * A combine function to combine INTERNAL states must accept nulls and
431  * ensure that the returned state is in the correct memory context.
432  */
433  if (aggTransType == INTERNALOID && func_strict(combinefn))
434  ereport(ERROR,
435  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
436  errmsg("combine function with \"%s\" transition type must not be declared STRICT",
437  format_type_be(aggTransType))));
438 
439  }
440 
441  /*
442  * Validate the serialization function, if present.
443  */
444  if (aggserialfnName)
445  {
446  fnArgs[0] = INTERNALOID;
447 
448  serialfn = lookup_agg_function(aggserialfnName, 1,
449  fnArgs, variadicArgType,
450  &rettype);
451 
452  if (rettype != BYTEAOID)
453  ereport(ERROR,
454  (errcode(ERRCODE_DATATYPE_MISMATCH),
455  errmsg("return type of serialization function %s is not %s",
456  NameListToString(aggserialfnName),
458  }
459 
460  /*
461  * Validate the deserialization function, if present.
462  */
463  if (aggdeserialfnName)
464  {
465  fnArgs[0] = BYTEAOID;
466  fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
467 
468  deserialfn = lookup_agg_function(aggdeserialfnName, 2,
469  fnArgs, variadicArgType,
470  &rettype);
471 
472  if (rettype != INTERNALOID)
473  ereport(ERROR,
474  (errcode(ERRCODE_DATATYPE_MISMATCH),
475  errmsg("return type of deserialization function %s is not %s",
476  NameListToString(aggdeserialfnName),
478  }
479 
480  /*
481  * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
482  * be polymorphic also, else parser will fail to deduce result type.
483  * (Note: given the previous test on transtype and inputs, this cannot
484  * happen, unless someone has snuck a finalfn definition into the catalogs
485  * that itself violates the rule against polymorphic result with no
486  * polymorphic input.)
487  */
488  if (IsPolymorphicType(finaltype) && !hasPolyArg)
489  ereport(ERROR,
490  (errcode(ERRCODE_DATATYPE_MISMATCH),
491  errmsg("cannot determine result data type"),
492  errdetail("An aggregate returning a polymorphic type "
493  "must have at least one polymorphic argument.")));
494 
495  /*
496  * Also, the return type can't be INTERNAL unless there's at least one
497  * INTERNAL argument. This is the same type-safety restriction we enforce
498  * for regular functions, but at the level of aggregates. We must test
499  * this explicitly because we allow INTERNAL as the transtype.
500  */
501  if (finaltype == INTERNALOID && !hasInternalArg)
502  ereport(ERROR,
503  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
504  errmsg("unsafe use of pseudo-type \"internal\""),
505  errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
506 
507  /*
508  * If a moving-aggregate implementation is supplied, look up its finalfn
509  * if any, and check that the implied aggregate result type matches the
510  * plain implementation.
511  */
512  if (OidIsValid(aggmTransType))
513  {
514  /* handle finalfn, if supplied */
515  if (aggmfinalfnName)
516  {
517  /*
518  * The arguments are figured the same way as for the regular
519  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
520  */
521  Oid ffnVariadicArgType = variadicArgType;
522 
523  fnArgs[0] = aggmTransType;
524  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
525  if (mfinalfnExtraArgs)
526  nargs_finalfn = numArgs + 1;
527  else
528  {
529  nargs_finalfn = numDirectArgs + 1;
530  if (numDirectArgs < numArgs)
531  {
532  /* variadic argument doesn't affect finalfn */
533  ffnVariadicArgType = InvalidOid;
534  }
535  }
536 
537  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
538  fnArgs, ffnVariadicArgType,
539  &rettype);
540 
541  /* As above, check strictness if mfinalfnExtraArgs is given */
542  if (mfinalfnExtraArgs && func_strict(mfinalfn))
543  ereport(ERROR,
544  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
545  errmsg("final function with extra arguments must not be declared STRICT")));
546  }
547  else
548  {
549  /*
550  * If no finalfn, aggregate result type is type of the state value
551  */
552  rettype = aggmTransType;
553  }
554  Assert(OidIsValid(rettype));
555  if (rettype != finaltype)
556  ereport(ERROR,
557  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
558  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
559  format_type_be(aggmTransType),
560  format_type_be(aggTransType))));
561  }
562 
563  /* handle sortop, if supplied */
564  if (aggsortopName)
565  {
566  if (numArgs != 1)
567  ereport(ERROR,
568  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
569  errmsg("sort operator can only be specified for single-argument aggregates")));
570  sortop = LookupOperName(NULL, aggsortopName,
571  aggArgTypes[0], aggArgTypes[0],
572  false, -1);
573  }
574 
575  /*
576  * permission checks on used types
577  */
578  for (i = 0; i < numArgs; i++)
579  {
580  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
581  if (aclresult != ACLCHECK_OK)
582  aclcheck_error_type(aclresult, aggArgTypes[i]);
583  }
584 
585  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
586  if (aclresult != ACLCHECK_OK)
587  aclcheck_error_type(aclresult, aggTransType);
588 
589  if (OidIsValid(aggmTransType))
590  {
591  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
592  if (aclresult != ACLCHECK_OK)
593  aclcheck_error_type(aclresult, aggmTransType);
594  }
595 
596  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
597  if (aclresult != ACLCHECK_OK)
598  aclcheck_error_type(aclresult, finaltype);
599 
600 
601  /*
602  * Everything looks okay. Try to create the pg_proc entry for the
603  * aggregate. (This could fail if there's already a conflicting entry.)
604  */
605 
606  myself = ProcedureCreate(aggName,
607  aggNamespace,
608  false, /* no replacement */
609  false, /* doesn't return a set */
610  finaltype, /* returnType */
611  GetUserId(), /* proowner */
612  INTERNALlanguageId, /* languageObjectId */
613  InvalidOid, /* no validator */
614  "aggregate_dummy", /* placeholder proc */
615  NULL, /* probin */
616  true, /* isAgg */
617  false, /* isWindowFunc */
618  false, /* security invoker (currently not
619  * definable for agg) */
620  false, /* isLeakProof */
621  false, /* isStrict (not needed for agg) */
622  PROVOLATILE_IMMUTABLE, /* volatility (not
623  * needed for agg) */
624  proparallel,
625  parameterTypes, /* paramTypes */
626  allParameterTypes, /* allParamTypes */
627  parameterModes, /* parameterModes */
628  parameterNames, /* parameterNames */
629  parameterDefaults, /* parameterDefaults */
630  PointerGetDatum(NULL), /* trftypes */
631  PointerGetDatum(NULL), /* proconfig */
632  1, /* procost */
633  0); /* prorows */
634  procOid = myself.objectId;
635 
636  /*
637  * Okay to create the pg_aggregate entry.
638  */
639 
640  /* initialize nulls and values */
641  for (i = 0; i < Natts_pg_aggregate; i++)
642  {
643  nulls[i] = false;
644  values[i] = (Datum) NULL;
645  }
646  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
647  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
648  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
649  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
650  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
651  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
652  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
653  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
654  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
655  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
656  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
657  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
658  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
659  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
660  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
661  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
662  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
663  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
664  if (agginitval)
665  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
666  else
667  nulls[Anum_pg_aggregate_agginitval - 1] = true;
668  if (aggminitval)
669  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
670  else
671  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
672 
674  tupDesc = aggdesc->rd_att;
675 
676  tup = heap_form_tuple(tupDesc, values, nulls);
677  CatalogTupleInsert(aggdesc, tup);
678 
679  heap_close(aggdesc, RowExclusiveLock);
680 
681  /*
682  * Create dependencies for the aggregate (above and beyond those already
683  * made by ProcedureCreate). Note: we don't need an explicit dependency
684  * on aggTransType since we depend on it indirectly through transfn.
685  * Likewise for aggmTransType using the mtransfunc, if it exists.
686  */
687 
688  /* Depends on transition function */
689  referenced.classId = ProcedureRelationId;
690  referenced.objectId = transfn;
691  referenced.objectSubId = 0;
692  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
693 
694  /* Depends on final function, if any */
695  if (OidIsValid(finalfn))
696  {
697  referenced.classId = ProcedureRelationId;
698  referenced.objectId = finalfn;
699  referenced.objectSubId = 0;
700  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
701  }
702 
703  /* Depends on combine function, if any */
704  if (OidIsValid(combinefn))
705  {
706  referenced.classId = ProcedureRelationId;
707  referenced.objectId = combinefn;
708  referenced.objectSubId = 0;
709  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
710  }
711 
712  /* Depends on serialization function, if any */
713  if (OidIsValid(serialfn))
714  {
715  referenced.classId = ProcedureRelationId;
716  referenced.objectId = serialfn;
717  referenced.objectSubId = 0;
718  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
719  }
720 
721  /* Depends on deserialization function, if any */
722  if (OidIsValid(deserialfn))
723  {
724  referenced.classId = ProcedureRelationId;
725  referenced.objectId = deserialfn;
726  referenced.objectSubId = 0;
727  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
728  }
729 
730  /* Depends on forward transition function, if any */
731  if (OidIsValid(mtransfn))
732  {
733  referenced.classId = ProcedureRelationId;
734  referenced.objectId = mtransfn;
735  referenced.objectSubId = 0;
736  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
737  }
738 
739  /* Depends on inverse transition function, if any */
740  if (OidIsValid(minvtransfn))
741  {
742  referenced.classId = ProcedureRelationId;
743  referenced.objectId = minvtransfn;
744  referenced.objectSubId = 0;
745  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
746  }
747 
748  /* Depends on final function, if any */
749  if (OidIsValid(mfinalfn))
750  {
751  referenced.classId = ProcedureRelationId;
752  referenced.objectId = mfinalfn;
753  referenced.objectSubId = 0;
754  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
755  }
756 
757  /* Depends on sort operator, if any */
758  if (OidIsValid(sortop))
759  {
760  referenced.classId = OperatorRelationId;
761  referenced.objectId = sortop;
762  referenced.objectSubId = 0;
763  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
764  }
765 
766  return myself;
767 }
768 
769 /*
770  * lookup_agg_function
771  * common code for finding transfn, invtransfn, finalfn, and combinefn
772  *
773  * Returns OID of function, and stores its return type into *rettype
774  *
775  * NB: must not scribble on input_types[], as we may re-use those
776  */
777 static Oid
779  int nargs,
780  Oid *input_types,
781  Oid variadicArgType,
782  Oid *rettype)
783 {
784  Oid fnOid;
785  bool retset;
786  int nvargs;
787  Oid vatype;
788  Oid *true_oid_array;
789  FuncDetailCode fdresult;
790  AclResult aclresult;
791  int i;
792 
793  /*
794  * func_get_detail looks up the function in the catalogs, does
795  * disambiguation for polymorphic functions, handles inheritance, and
796  * returns the funcid and type and set or singleton status of the
797  * function's return value. it also returns the true argument types to
798  * the function.
799  */
800  fdresult = func_get_detail(fnName, NIL, NIL,
801  nargs, input_types, false, false,
802  &fnOid, rettype, &retset,
803  &nvargs, &vatype,
804  &true_oid_array, NULL);
805 
806  /* only valid case is a normal function not returning a set */
807  if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
808  ereport(ERROR,
809  (errcode(ERRCODE_UNDEFINED_FUNCTION),
810  errmsg("function %s does not exist",
811  func_signature_string(fnName, nargs,
812  NIL, input_types))));
813  if (retset)
814  ereport(ERROR,
815  (errcode(ERRCODE_DATATYPE_MISMATCH),
816  errmsg("function %s returns a set",
817  func_signature_string(fnName, nargs,
818  NIL, input_types))));
819 
820  /*
821  * If the agg is declared to take VARIADIC ANY, the underlying functions
822  * had better be declared that way too, else they may receive too many
823  * parameters; but func_get_detail would have been happy with plain ANY.
824  * (Probably nothing very bad would happen, but it wouldn't work as the
825  * user expects.) Other combinations should work without any special
826  * pushups, given that we told func_get_detail not to expand VARIADIC.
827  */
828  if (variadicArgType == ANYOID && vatype != ANYOID)
829  ereport(ERROR,
830  (errcode(ERRCODE_DATATYPE_MISMATCH),
831  errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
832  func_signature_string(fnName, nargs,
833  NIL, input_types))));
834 
835  /*
836  * If there are any polymorphic types involved, enforce consistency, and
837  * possibly refine the result type. It's OK if the result is still
838  * polymorphic at this point, though.
839  */
840  *rettype = enforce_generic_type_consistency(input_types,
841  true_oid_array,
842  nargs,
843  *rettype,
844  true);
845 
846  /*
847  * func_get_detail will find functions requiring run-time argument type
848  * coercion, but nodeAgg.c isn't prepared to deal with that
849  */
850  for (i = 0; i < nargs; i++)
851  {
852  if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
853  ereport(ERROR,
854  (errcode(ERRCODE_DATATYPE_MISMATCH),
855  errmsg("function %s requires run-time type coercion",
856  func_signature_string(fnName, nargs,
857  NIL, true_oid_array))));
858  }
859 
860  /* Check aggregate creator has permission to call the function */
861  aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
862  if (aclresult != ACLCHECK_OK)
863  aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(fnOid));
864 
865  return fnOid;
866 }
ObjectAddress AggregateCreate(const char *aggName, Oid aggNamespace, char aggKind, int numArgs, int numDirectArgs, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Oid variadicArgType, List *aggtransfnName, List *aggfinalfnName, List *aggcombinefnName, List *aggserialfnName, List *aggdeserialfnName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
Definition: pg_aggregate.c:47
#define NIL
Definition: pg_list.h:69
Definition: c.h:478
#define OperatorRelationId
Definition: pg_operator.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define PROVOLATILE_IMMUTABLE
Definition: pg_proc.h:5434
#define Anum_pg_aggregate_aggtransspace
Definition: pg_aggregate.h:110
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:113
#define INTERNALlanguageId
Definition: pg_language.h:74
Oid GetUserId(void)
Definition: miscinit.c:283
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:850
#define PointerGetDatum(X)
Definition: postgres.h:562
#define Anum_pg_aggregate_aggminvtransfn
Definition: pg_aggregate.h:104
#define ProcedureRelationId
Definition: pg_proc.h:33
#define Anum_pg_aggregate_aggdeserialfn
Definition: pg_aggregate.h:102
#define Int16GetDatum(X)
Definition: postgres.h:457
#define Anum_pg_aggregate_aggtransfn
Definition: pg_aggregate.h:98
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:102
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3440
signed int int32
Definition: c.h:256
#define AggregateRelationId
Definition: pg_aggregate.h:53
#define Anum_pg_aggregate_aggserialfn
Definition: pg_aggregate.h:101
#define FUNC_MAX_ARGS
#define AGGKIND_IS_ORDERED_SET(kind)
Definition: pg_aggregate.h:129
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define IsPolymorphicType(typid)
Definition: pg_type.h:741
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define Anum_pg_aggregate_aggfnoid
Definition: pg_aggregate.h:95
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1380
Oid enforce_generic_type_consistency(Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
#define Anum_pg_aggregate_aggcombinefn
Definition: pg_aggregate.h:100
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:486
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3382
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ANYOID
Definition: pg_type.h:682
FuncDetailCode
Definition: parse_func.h:22
#define ACL_USAGE
Definition: parsenodes.h:73
#define Anum_pg_aggregate_aggmtranstype
Definition: pg_aggregate.h:111
#define ereport(elevel, rest)
Definition: elog.h:122
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:778
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1889
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define Natts_pg_aggregate
Definition: pg_aggregate.h:94
#define Anum_pg_aggregate_aggmfinalextra
Definition: pg_aggregate.h:107
char * NameListToString(List *names)
Definition: namespace.c:2953
#define Anum_pg_aggregate_aggsortop
Definition: pg_aggregate.h:108
#define Anum_pg_aggregate_aggkind
Definition: pg_aggregate.h:96
#define Anum_pg_aggregate_aggminitval
Definition: pg_aggregate.h:114
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
#define Anum_pg_aggregate_aggfinalextra
Definition: pg_aggregate.h:106
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
TupleDesc rd_att
Definition: rel.h:115
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
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, bool isAgg, bool isWindowFunc, 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, float4 procost, float4 prorows)
Definition: pg_proc.c:67
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
#define INTERNALOID
Definition: pg_type.h:694
#define Anum_pg_aggregate_aggmtransfn
Definition: pg_aggregate.h:103
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_aggregate_aggfinalfn
Definition: pg_aggregate.h:99
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1264
bool func_strict(Oid funcid)
Definition: lsyscache.c:1533
#define CharGetDatum(X)
Definition: postgres.h:422
#define BYTEAOID
Definition: pg_type.h:292
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define Int32GetDatum(X)
Definition: postgres.h:485
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:72
#define Anum_pg_aggregate_aggnumdirectargs
Definition: pg_aggregate.h:97
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4429
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
#define Anum_pg_aggregate_aggmtransspace
Definition: pg_aggregate.h:112
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4517
#define AGGKIND_HYPOTHETICAL
Definition: pg_aggregate.h:126
Definition: pg_list.h:45
#define Anum_pg_aggregate_aggmfinalfn
Definition: pg_aggregate.h:105
#define Anum_pg_aggregate_aggtranstype
Definition: pg_aggregate.h:109