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-2020, 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  AclResult aclresult;
109 
110  /* sanity checks (caller should have caught these) */
111  if (!aggName)
112  elog(ERROR, "no aggregate name supplied");
113 
114  if (!aggtransfnName)
115  elog(ERROR, "aggregate must have a transition function");
116 
117  if (numDirectArgs < 0 || numDirectArgs > numArgs)
118  elog(ERROR, "incorrect number of direct arguments for aggregate");
119 
120  /*
121  * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
122  * and/or finalfn will be unrepresentable in pg_proc. We must check now
123  * to protect fixed-size arrays here and possibly in called functions.
124  */
125  if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
126  ereport(ERROR,
127  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
128  errmsg_plural("aggregates cannot have more than %d argument",
129  "aggregates cannot have more than %d arguments",
130  FUNC_MAX_ARGS - 1,
131  FUNC_MAX_ARGS - 1)));
132 
133  /*
134  * If transtype is polymorphic, must have polymorphic argument also; else
135  * we will have no way to deduce the actual transtype.
136  */
137  detailmsg = check_valid_polymorphic_signature(aggTransType,
138  aggArgTypes,
139  numArgs);
140  if (detailmsg)
141  ereport(ERROR,
142  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
143  errmsg("cannot determine transition data type"),
144  errdetail_internal("%s", detailmsg)));
145 
146  /*
147  * Likewise for moving-aggregate transtype, if any
148  */
149  if (OidIsValid(aggmTransType))
150  {
151  detailmsg = check_valid_polymorphic_signature(aggmTransType,
152  aggArgTypes,
153  numArgs);
154  if (detailmsg)
155  ereport(ERROR,
156  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
157  errmsg("cannot determine transition data type"),
158  errdetail_internal("%s", detailmsg)));
159  }
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 arguments, each of which is the trans
413  * type. VARIADIC doesn't affect it.
414  */
415  fnArgs[0] = aggTransType;
416  fnArgs[1] = aggTransType;
417 
418  combinefn = lookup_agg_function(aggcombinefnName, 2,
419  fnArgs, InvalidOid,
420  &combineType);
421 
422  /* Ensure the return type matches the aggregate's trans type */
423  if (combineType != aggTransType)
424  ereport(ERROR,
425  (errcode(ERRCODE_DATATYPE_MISMATCH),
426  errmsg("return type of combine function %s is not %s",
427  NameListToString(aggcombinefnName),
428  format_type_be(aggTransType))));
429 
430  /*
431  * A combine function to combine INTERNAL states must accept nulls and
432  * ensure that the returned state is in the correct memory context. We
433  * cannot directly check the latter, but we can check the former.
434  */
435  if (aggTransType == INTERNALOID && func_strict(combinefn))
436  ereport(ERROR,
437  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
438  errmsg("combine function with transition type %s must not be declared STRICT",
439  format_type_be(aggTransType))));
440  }
441 
442  /*
443  * Validate the serialization function, if present.
444  */
445  if (aggserialfnName)
446  {
447  /* signature is always serialize(internal) returns bytea */
448  fnArgs[0] = INTERNALOID;
449 
450  serialfn = lookup_agg_function(aggserialfnName, 1,
451  fnArgs, InvalidOid,
452  &rettype);
453 
454  if (rettype != BYTEAOID)
455  ereport(ERROR,
456  (errcode(ERRCODE_DATATYPE_MISMATCH),
457  errmsg("return type of serialization function %s is not %s",
458  NameListToString(aggserialfnName),
459  format_type_be(BYTEAOID))));
460  }
461 
462  /*
463  * Validate the deserialization function, if present.
464  */
465  if (aggdeserialfnName)
466  {
467  /* signature is always deserialize(bytea, internal) returns internal */
468  fnArgs[0] = BYTEAOID;
469  fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
470 
471  deserialfn = lookup_agg_function(aggdeserialfnName, 2,
472  fnArgs, InvalidOid,
473  &rettype);
474 
475  if (rettype != INTERNALOID)
476  ereport(ERROR,
477  (errcode(ERRCODE_DATATYPE_MISMATCH),
478  errmsg("return type of deserialization function %s is not %s",
479  NameListToString(aggdeserialfnName),
480  format_type_be(INTERNALOID))));
481  }
482 
483  /*
484  * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
485  * be polymorphic also, else parser will fail to deduce result type.
486  * (Note: given the previous test on transtype and inputs, this cannot
487  * happen, unless someone has snuck a finalfn definition into the catalogs
488  * that itself violates the rule against polymorphic result with no
489  * polymorphic input.)
490  */
491  detailmsg = check_valid_polymorphic_signature(finaltype,
492  aggArgTypes,
493  numArgs);
494  if (detailmsg)
495  ereport(ERROR,
496  (errcode(ERRCODE_DATATYPE_MISMATCH),
497  errmsg("cannot determine result data type"),
498  errdetail_internal("%s", detailmsg)));
499 
500  /*
501  * Also, the return type can't be INTERNAL unless there's at least one
502  * INTERNAL argument. This is the same type-safety restriction we enforce
503  * for regular functions, but at the level of aggregates. We must test
504  * this explicitly because we allow INTERNAL as the transtype.
505  */
506  detailmsg = check_valid_internal_signature(finaltype,
507  aggArgTypes,
508  numArgs);
509  if (detailmsg)
510  ereport(ERROR,
511  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
512  errmsg("unsafe use of pseudo-type \"internal\""),
513  errdetail_internal("%s", detailmsg)));
514 
515  /*
516  * If a moving-aggregate implementation is supplied, look up its finalfn
517  * if any, and check that the implied aggregate result type matches the
518  * plain implementation.
519  */
520  if (OidIsValid(aggmTransType))
521  {
522  /* handle finalfn, if supplied */
523  if (aggmfinalfnName)
524  {
525  /*
526  * The arguments are figured the same way as for the regular
527  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
528  */
529  Oid ffnVariadicArgType = variadicArgType;
530 
531  fnArgs[0] = aggmTransType;
532  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
533  if (mfinalfnExtraArgs)
534  nargs_finalfn = numArgs + 1;
535  else
536  {
537  nargs_finalfn = numDirectArgs + 1;
538  if (numDirectArgs < numArgs)
539  {
540  /* variadic argument doesn't affect finalfn */
541  ffnVariadicArgType = InvalidOid;
542  }
543  }
544 
545  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
546  fnArgs, ffnVariadicArgType,
547  &rettype);
548 
549  /* As above, check strictness if mfinalfnExtraArgs is given */
550  if (mfinalfnExtraArgs && func_strict(mfinalfn))
551  ereport(ERROR,
552  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
553  errmsg("final function with extra arguments must not be declared STRICT")));
554  }
555  else
556  {
557  /*
558  * If no finalfn, aggregate result type is type of the state value
559  */
560  rettype = aggmTransType;
561  }
562  Assert(OidIsValid(rettype));
563  if (rettype != finaltype)
564  ereport(ERROR,
565  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
566  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
567  format_type_be(aggmTransType),
568  format_type_be(aggTransType))));
569  }
570 
571  /* handle sortop, if supplied */
572  if (aggsortopName)
573  {
574  if (numArgs != 1)
575  ereport(ERROR,
576  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
577  errmsg("sort operator can only be specified for single-argument aggregates")));
578  sortop = LookupOperName(NULL, aggsortopName,
579  aggArgTypes[0], aggArgTypes[0],
580  false, -1);
581  }
582 
583  /*
584  * permission checks on used types
585  */
586  for (i = 0; i < numArgs; i++)
587  {
588  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
589  if (aclresult != ACLCHECK_OK)
590  aclcheck_error_type(aclresult, aggArgTypes[i]);
591  }
592 
593  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
594  if (aclresult != ACLCHECK_OK)
595  aclcheck_error_type(aclresult, aggTransType);
596 
597  if (OidIsValid(aggmTransType))
598  {
599  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
600  if (aclresult != ACLCHECK_OK)
601  aclcheck_error_type(aclresult, aggmTransType);
602  }
603 
604  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
605  if (aclresult != ACLCHECK_OK)
606  aclcheck_error_type(aclresult, finaltype);
607 
608 
609  /*
610  * Everything looks okay. Try to create the pg_proc entry for the
611  * aggregate. (This could fail if there's already a conflicting entry.)
612  */
613 
614  myself = ProcedureCreate(aggName,
615  aggNamespace,
616  replace, /* maybe replacement */
617  false, /* doesn't return a set */
618  finaltype, /* returnType */
619  GetUserId(), /* proowner */
620  INTERNALlanguageId, /* languageObjectId */
621  InvalidOid, /* no validator */
622  "aggregate_dummy", /* placeholder proc */
623  NULL, /* probin */
624  PROKIND_AGGREGATE,
625  false, /* security invoker (currently not
626  * definable for agg) */
627  false, /* isLeakProof */
628  false, /* isStrict (not needed for agg) */
629  PROVOLATILE_IMMUTABLE, /* volatility (not needed
630  * for agg) */
631  proparallel,
632  parameterTypes, /* paramTypes */
633  allParameterTypes, /* allParamTypes */
634  parameterModes, /* parameterModes */
635  parameterNames, /* parameterNames */
636  parameterDefaults, /* parameterDefaults */
637  PointerGetDatum(NULL), /* trftypes */
638  PointerGetDatum(NULL), /* proconfig */
639  InvalidOid, /* no prosupport */
640  1, /* procost */
641  0); /* prorows */
642  procOid = myself.objectId;
643 
644  /*
645  * Okay to create the pg_aggregate entry.
646  */
647  aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
648  tupDesc = aggdesc->rd_att;
649 
650  /* initialize nulls and values */
651  for (i = 0; i < Natts_pg_aggregate; i++)
652  {
653  nulls[i] = false;
654  values[i] = (Datum) NULL;
655  replaces[i] = true;
656  }
657  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
658  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
659  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
660  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
661  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
662  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
663  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
664  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
665  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
666  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
667  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
668  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
669  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
670  values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
671  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
672  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
673  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
674  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
675  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
676  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
677  if (agginitval)
678  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
679  else
680  nulls[Anum_pg_aggregate_agginitval - 1] = true;
681  if (aggminitval)
682  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
683  else
684  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
685 
686  if (replace)
687  oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
688  else
689  oldtup = NULL;
690 
691  if (HeapTupleIsValid(oldtup))
692  {
693  Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
694 
695  /*
696  * If we're replacing an existing entry, we need to validate that
697  * we're not changing anything that would break callers. Specifically
698  * we must not change aggkind or aggnumdirectargs, which affect how an
699  * aggregate call is treated in parse analysis.
700  */
701  if (aggKind != oldagg->aggkind)
702  ereport(ERROR,
703  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
704  errmsg("cannot change routine kind"),
705  (oldagg->aggkind == AGGKIND_NORMAL ?
706  errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
707  oldagg->aggkind == AGGKIND_ORDERED_SET ?
708  errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
709  oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
710  errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
711  0)));
712  if (numDirectArgs != oldagg->aggnumdirectargs)
713  ereport(ERROR,
714  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
715  errmsg("cannot change number of direct arguments of an aggregate function")));
716 
717  replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
718  replaces[Anum_pg_aggregate_aggkind - 1] = false;
719  replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
720 
721  tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
722  CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
723  ReleaseSysCache(oldtup);
724  }
725  else
726  {
727  tup = heap_form_tuple(tupDesc, values, nulls);
728  CatalogTupleInsert(aggdesc, tup);
729  }
730 
731  table_close(aggdesc, RowExclusiveLock);
732 
733  /*
734  * Create dependencies for the aggregate (above and beyond those already
735  * made by ProcedureCreate). Note: we don't need an explicit dependency
736  * on aggTransType since we depend on it indirectly through transfn.
737  * Likewise for aggmTransType using the mtransfn, if it exists.
738  *
739  * If we're replacing an existing definition, ProcedureCreate deleted all
740  * our existing dependencies, so we have to do the same things here either
741  * way.
742  */
743 
744  /* Depends on transition function */
745  ObjectAddressSet(referenced, ProcedureRelationId, transfn);
746  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
747 
748  /* Depends on final function, if any */
749  if (OidIsValid(finalfn))
750  {
751  ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
752  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
753  }
754 
755  /* Depends on combine function, if any */
756  if (OidIsValid(combinefn))
757  {
758  ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
759  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
760  }
761 
762  /* Depends on serialization function, if any */
763  if (OidIsValid(serialfn))
764  {
765  ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
766  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
767  }
768 
769  /* Depends on deserialization function, if any */
770  if (OidIsValid(deserialfn))
771  {
772  ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
773  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
774  }
775 
776  /* Depends on forward transition function, if any */
777  if (OidIsValid(mtransfn))
778  {
779  ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
780  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
781  }
782 
783  /* Depends on inverse transition function, if any */
784  if (OidIsValid(minvtransfn))
785  {
786  ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
787  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
788  }
789 
790  /* Depends on final function, if any */
791  if (OidIsValid(mfinalfn))
792  {
793  ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
794  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
795  }
796 
797  /* Depends on sort operator, if any */
798  if (OidIsValid(sortop))
799  {
800  ObjectAddressSet(referenced, OperatorRelationId, sortop);
801  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
802  }
803 
804  return myself;
805 }
806 
807 /*
808  * lookup_agg_function
809  * common code for finding aggregate support functions
810  *
811  * fnName: possibly-schema-qualified function name
812  * nargs, input_types: expected function argument types
813  * variadicArgType: type of variadic argument if any, else InvalidOid
814  *
815  * Returns OID of function, and stores its return type into *rettype
816  *
817  * NB: must not scribble on input_types[], as we may re-use those
818  */
819 static Oid
821  int nargs,
822  Oid *input_types,
823  Oid variadicArgType,
824  Oid *rettype)
825 {
826  Oid fnOid;
827  bool retset;
828  int nvargs;
829  Oid vatype;
830  Oid *true_oid_array;
831  FuncDetailCode fdresult;
832  AclResult aclresult;
833  int i;
834 
835  /*
836  * func_get_detail looks up the function in the catalogs, does
837  * disambiguation for polymorphic functions, handles inheritance, and
838  * returns the funcid and type and set or singleton status of the
839  * function's return value. it also returns the true argument types to
840  * the function.
841  */
842  fdresult = func_get_detail(fnName, NIL, NIL,
843  nargs, input_types, false, false,
844  &fnOid, rettype, &retset,
845  &nvargs, &vatype,
846  &true_oid_array, NULL);
847 
848  /* only valid case is a normal function not returning a set */
849  if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
850  ereport(ERROR,
851  (errcode(ERRCODE_UNDEFINED_FUNCTION),
852  errmsg("function %s does not exist",
853  func_signature_string(fnName, nargs,
854  NIL, input_types))));
855  if (retset)
856  ereport(ERROR,
857  (errcode(ERRCODE_DATATYPE_MISMATCH),
858  errmsg("function %s returns a set",
859  func_signature_string(fnName, nargs,
860  NIL, input_types))));
861 
862  /*
863  * If the agg is declared to take VARIADIC ANY, the underlying functions
864  * had better be declared that way too, else they may receive too many
865  * parameters; but func_get_detail would have been happy with plain ANY.
866  * (Probably nothing very bad would happen, but it wouldn't work as the
867  * user expects.) Other combinations should work without any special
868  * pushups, given that we told func_get_detail not to expand VARIADIC.
869  */
870  if (variadicArgType == ANYOID && vatype != ANYOID)
871  ereport(ERROR,
872  (errcode(ERRCODE_DATATYPE_MISMATCH),
873  errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
874  func_signature_string(fnName, nargs,
875  NIL, input_types))));
876 
877  /*
878  * If there are any polymorphic types involved, enforce consistency, and
879  * possibly refine the result type. It's OK if the result is still
880  * polymorphic at this point, though.
881  */
882  *rettype = enforce_generic_type_consistency(input_types,
883  true_oid_array,
884  nargs,
885  *rettype,
886  true);
887 
888  /*
889  * func_get_detail will find functions requiring run-time argument type
890  * coercion, but nodeAgg.c isn't prepared to deal with that
891  */
892  for (i = 0; i < nargs; i++)
893  {
894  if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
895  ereport(ERROR,
896  (errcode(ERRCODE_DATATYPE_MISMATCH),
897  errmsg("function %s requires run-time type coercion",
898  func_signature_string(fnName, nargs,
899  NIL, true_oid_array))));
900  }
901 
902  /* Check aggregate creator has permission to call the function */
903  aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
904  if (aclresult != ACLCHECK_OK)
905  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
906 
907  return fnOid;
908 }
#define NIL
Definition: pg_list.h:65
Definition: c.h:594
Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
Oid GetUserId(void)
Definition: miscinit.c:448
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:934
#define PointerGetDatum(X)
Definition: postgres.h:556
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, 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:69
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
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:1020
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
signed int int32
Definition: c.h:355
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
#define FUNC_MAX_ARGS
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
ItemPointerData t_self
Definition: htup.h:65
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:602
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
FuncDetailCode
Definition: parse_func.h:22
#define ACL_USAGE
Definition: parsenodes.h:82
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:820
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
TupleDesc rd_att
Definition: rel.h:110
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
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:1382
bool func_strict(Oid funcid)
Definition: lsyscache.c:1673
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:214
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:87
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
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4675
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183