PostgreSQL Source Code  git master
pg_aggregate.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_aggregate.c:

Go to the source code of this file.

Functions

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

Function Documentation

◆ AggregateCreate()

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

Definition at line 46 of file pg_aggregate.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, Assert, BoolGetDatum, CatalogTupleInsert(), CharGetDatum, ObjectAddress::classId, CStringGetTextDatum, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), errmsg_plural(), ERROR, format_type_be(), FUNC_MAX_ARGS, func_strict(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_open(), HeapTupleIsValid, i, Int16GetDatum, Int32GetDatum, InvalidOid, IsBinaryCoercible(), lookup_agg_function(), LookupOperName(), NameListToString(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, pg_type_aclcheck(), PointerGetDatum, ProcedureCreate(), PROCOID, RelationData::rd_att, recordDependencyOn(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), values, and oidvector::values.

Referenced by DefineAggregate().

77 {
78  Relation aggdesc;
79  HeapTuple tup;
80  bool nulls[Natts_pg_aggregate];
81  Datum values[Natts_pg_aggregate];
82  Form_pg_proc proc;
83  Oid transfn;
84  Oid finalfn = InvalidOid; /* can be omitted */
85  Oid combinefn = InvalidOid; /* can be omitted */
86  Oid serialfn = InvalidOid; /* can be omitted */
87  Oid deserialfn = InvalidOid; /* can be omitted */
88  Oid mtransfn = InvalidOid; /* can be omitted */
89  Oid minvtransfn = InvalidOid; /* can be omitted */
90  Oid mfinalfn = InvalidOid; /* can be omitted */
91  Oid sortop = InvalidOid; /* can be omitted */
92  Oid *aggArgTypes = parameterTypes->values;
93  bool hasPolyArg;
94  bool hasInternalArg;
95  bool mtransIsStrict = false;
96  Oid rettype;
97  Oid finaltype;
98  Oid fnArgs[FUNC_MAX_ARGS];
99  int nargs_transfn;
100  int nargs_finalfn;
101  Oid procOid;
102  TupleDesc tupDesc;
103  int i;
104  ObjectAddress myself,
105  referenced;
106  AclResult aclresult;
107 
108  /* sanity checks (caller should have caught these) */
109  if (!aggName)
110  elog(ERROR, "no aggregate name supplied");
111 
112  if (!aggtransfnName)
113  elog(ERROR, "aggregate must have a transition function");
114 
115  if (numDirectArgs < 0 || numDirectArgs > numArgs)
116  elog(ERROR, "incorrect number of direct args for aggregate");
117 
118  /*
119  * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
120  * and/or finalfn will be unrepresentable in pg_proc. We must check now
121  * to protect fixed-size arrays here and possibly in called functions.
122  */
123  if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
124  ereport(ERROR,
125  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
126  errmsg_plural("aggregates cannot have more than %d argument",
127  "aggregates cannot have more than %d arguments",
128  FUNC_MAX_ARGS - 1,
129  FUNC_MAX_ARGS - 1)));
130 
131  /* check for polymorphic and INTERNAL arguments */
132  hasPolyArg = false;
133  hasInternalArg = false;
134  for (i = 0; i < numArgs; i++)
135  {
136  if (IsPolymorphicType(aggArgTypes[i]))
137  hasPolyArg = true;
138  else if (aggArgTypes[i] == INTERNALOID)
139  hasInternalArg = true;
140  }
141 
142  /*
143  * If transtype is polymorphic, must have polymorphic argument also; else
144  * we will have no way to deduce the actual transtype.
145  */
146  if (IsPolymorphicType(aggTransType) && !hasPolyArg)
147  ereport(ERROR,
148  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
149  errmsg("cannot determine transition data type"),
150  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
151 
152  /*
153  * Likewise for moving-aggregate transtype, if any
154  */
155  if (OidIsValid(aggmTransType) &&
156  IsPolymorphicType(aggmTransType) && !hasPolyArg)
157  ereport(ERROR,
158  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
159  errmsg("cannot determine transition data type"),
160  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
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 argument, each of which is the trans
414  * type
415  */
416  fnArgs[0] = aggTransType;
417  fnArgs[1] = aggTransType;
418 
419  combinefn = lookup_agg_function(aggcombinefnName, 2, fnArgs,
420  variadicArgType, &combineType);
421 
422  /* Ensure the return type matches the aggregates 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.
433  */
434  if (aggTransType == INTERNALOID && func_strict(combinefn))
435  ereport(ERROR,
436  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
437  errmsg("combine function with transition type %s must not be declared STRICT",
438  format_type_be(aggTransType))));
439 
440  }
441 
442  /*
443  * Validate the serialization function, if present.
444  */
445  if (aggserialfnName)
446  {
447  fnArgs[0] = INTERNALOID;
448 
449  serialfn = lookup_agg_function(aggserialfnName, 1,
450  fnArgs, variadicArgType,
451  &rettype);
452 
453  if (rettype != BYTEAOID)
454  ereport(ERROR,
455  (errcode(ERRCODE_DATATYPE_MISMATCH),
456  errmsg("return type of serialization function %s is not %s",
457  NameListToString(aggserialfnName),
458  format_type_be(BYTEAOID))));
459  }
460 
461  /*
462  * Validate the deserialization function, if present.
463  */
464  if (aggdeserialfnName)
465  {
466  fnArgs[0] = BYTEAOID;
467  fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
468 
469  deserialfn = lookup_agg_function(aggdeserialfnName, 2,
470  fnArgs, variadicArgType,
471  &rettype);
472 
473  if (rettype != INTERNALOID)
474  ereport(ERROR,
475  (errcode(ERRCODE_DATATYPE_MISMATCH),
476  errmsg("return type of deserialization function %s is not %s",
477  NameListToString(aggdeserialfnName),
478  format_type_be(INTERNALOID))));
479  }
480 
481  /*
482  * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
483  * be polymorphic also, else parser will fail to deduce result type.
484  * (Note: given the previous test on transtype and inputs, this cannot
485  * happen, unless someone has snuck a finalfn definition into the catalogs
486  * that itself violates the rule against polymorphic result with no
487  * polymorphic input.)
488  */
489  if (IsPolymorphicType(finaltype) && !hasPolyArg)
490  ereport(ERROR,
491  (errcode(ERRCODE_DATATYPE_MISMATCH),
492  errmsg("cannot determine result data type"),
493  errdetail("An aggregate returning a polymorphic type "
494  "must have at least one polymorphic argument.")));
495 
496  /*
497  * Also, the return type can't be INTERNAL unless there's at least one
498  * INTERNAL argument. This is the same type-safety restriction we enforce
499  * for regular functions, but at the level of aggregates. We must test
500  * this explicitly because we allow INTERNAL as the transtype.
501  */
502  if (finaltype == INTERNALOID && !hasInternalArg)
503  ereport(ERROR,
504  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
505  errmsg("unsafe use of pseudo-type \"internal\""),
506  errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
507 
508  /*
509  * If a moving-aggregate implementation is supplied, look up its finalfn
510  * if any, and check that the implied aggregate result type matches the
511  * plain implementation.
512  */
513  if (OidIsValid(aggmTransType))
514  {
515  /* handle finalfn, if supplied */
516  if (aggmfinalfnName)
517  {
518  /*
519  * The arguments are figured the same way as for the regular
520  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
521  */
522  Oid ffnVariadicArgType = variadicArgType;
523 
524  fnArgs[0] = aggmTransType;
525  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
526  if (mfinalfnExtraArgs)
527  nargs_finalfn = numArgs + 1;
528  else
529  {
530  nargs_finalfn = numDirectArgs + 1;
531  if (numDirectArgs < numArgs)
532  {
533  /* variadic argument doesn't affect finalfn */
534  ffnVariadicArgType = InvalidOid;
535  }
536  }
537 
538  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
539  fnArgs, ffnVariadicArgType,
540  &rettype);
541 
542  /* As above, check strictness if mfinalfnExtraArgs is given */
543  if (mfinalfnExtraArgs && func_strict(mfinalfn))
544  ereport(ERROR,
545  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
546  errmsg("final function with extra arguments must not be declared STRICT")));
547  }
548  else
549  {
550  /*
551  * If no finalfn, aggregate result type is type of the state value
552  */
553  rettype = aggmTransType;
554  }
555  Assert(OidIsValid(rettype));
556  if (rettype != finaltype)
557  ereport(ERROR,
558  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
559  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
560  format_type_be(aggmTransType),
561  format_type_be(aggTransType))));
562  }
563 
564  /* handle sortop, if supplied */
565  if (aggsortopName)
566  {
567  if (numArgs != 1)
568  ereport(ERROR,
569  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
570  errmsg("sort operator can only be specified for single-argument aggregates")));
571  sortop = LookupOperName(NULL, aggsortopName,
572  aggArgTypes[0], aggArgTypes[0],
573  false, -1);
574  }
575 
576  /*
577  * permission checks on used types
578  */
579  for (i = 0; i < numArgs; i++)
580  {
581  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
582  if (aclresult != ACLCHECK_OK)
583  aclcheck_error_type(aclresult, aggArgTypes[i]);
584  }
585 
586  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
587  if (aclresult != ACLCHECK_OK)
588  aclcheck_error_type(aclresult, aggTransType);
589 
590  if (OidIsValid(aggmTransType))
591  {
592  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
593  if (aclresult != ACLCHECK_OK)
594  aclcheck_error_type(aclresult, aggmTransType);
595  }
596 
597  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
598  if (aclresult != ACLCHECK_OK)
599  aclcheck_error_type(aclresult, finaltype);
600 
601 
602  /*
603  * Everything looks okay. Try to create the pg_proc entry for the
604  * aggregate. (This could fail if there's already a conflicting entry.)
605  */
606 
607  myself = ProcedureCreate(aggName,
608  aggNamespace,
609  false, /* no replacement */
610  false, /* doesn't return a set */
611  finaltype, /* returnType */
612  GetUserId(), /* proowner */
613  INTERNALlanguageId, /* languageObjectId */
614  InvalidOid, /* no validator */
615  "aggregate_dummy", /* placeholder proc */
616  NULL, /* probin */
617  PROKIND_AGGREGATE,
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 needed
623  * 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_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
660  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
661  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
662  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
663  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
664  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
665  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
666  if (agginitval)
667  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
668  else
669  nulls[Anum_pg_aggregate_agginitval - 1] = true;
670  if (aggminitval)
671  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
672  else
673  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
674 
675  aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
676  tupDesc = aggdesc->rd_att;
677 
678  tup = heap_form_tuple(tupDesc, values, nulls);
679  CatalogTupleInsert(aggdesc, tup);
680 
681  heap_close(aggdesc, RowExclusiveLock);
682 
683  /*
684  * Create dependencies for the aggregate (above and beyond those already
685  * made by ProcedureCreate). Note: we don't need an explicit dependency
686  * on aggTransType since we depend on it indirectly through transfn.
687  * Likewise for aggmTransType using the mtransfunc, if it exists.
688  */
689 
690  /* Depends on transition function */
691  referenced.classId = ProcedureRelationId;
692  referenced.objectId = transfn;
693  referenced.objectSubId = 0;
694  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
695 
696  /* Depends on final function, if any */
697  if (OidIsValid(finalfn))
698  {
699  referenced.classId = ProcedureRelationId;
700  referenced.objectId = finalfn;
701  referenced.objectSubId = 0;
702  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
703  }
704 
705  /* Depends on combine function, if any */
706  if (OidIsValid(combinefn))
707  {
708  referenced.classId = ProcedureRelationId;
709  referenced.objectId = combinefn;
710  referenced.objectSubId = 0;
711  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
712  }
713 
714  /* Depends on serialization function, if any */
715  if (OidIsValid(serialfn))
716  {
717  referenced.classId = ProcedureRelationId;
718  referenced.objectId = serialfn;
719  referenced.objectSubId = 0;
720  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
721  }
722 
723  /* Depends on deserialization function, if any */
724  if (OidIsValid(deserialfn))
725  {
726  referenced.classId = ProcedureRelationId;
727  referenced.objectId = deserialfn;
728  referenced.objectSubId = 0;
729  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
730  }
731 
732  /* Depends on forward transition function, if any */
733  if (OidIsValid(mtransfn))
734  {
735  referenced.classId = ProcedureRelationId;
736  referenced.objectId = mtransfn;
737  referenced.objectSubId = 0;
738  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
739  }
740 
741  /* Depends on inverse transition function, if any */
742  if (OidIsValid(minvtransfn))
743  {
744  referenced.classId = ProcedureRelationId;
745  referenced.objectId = minvtransfn;
746  referenced.objectSubId = 0;
747  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
748  }
749 
750  /* Depends on final function, if any */
751  if (OidIsValid(mfinalfn))
752  {
753  referenced.classId = ProcedureRelationId;
754  referenced.objectId = mfinalfn;
755  referenced.objectSubId = 0;
756  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
757  }
758 
759  /* Depends on sort operator, if any */
760  if (OidIsValid(sortop))
761  {
762  referenced.classId = OperatorRelationId;
763  referenced.objectId = sortop;
764  referenced.objectSubId = 0;
765  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
766  }
767 
768  return myself;
769 }
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, float4 procost, float4 prorows)
Definition: pg_proc.c:66
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Oid GetUserId(void)
Definition: miscinit.c:379
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:850
#define PointerGetDatum(X)
Definition: postgres.h:539
#define Int16GetDatum(X)
Definition: postgres.h:434
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
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:1074
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
#define FUNC_MAX_ARGS
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:563
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ACL_USAGE
Definition: parsenodes.h:82
#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:780
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3082
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:132
#define BoolGetDatum(X)
Definition: postgres.h:385
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
bool func_strict(Oid funcid)
Definition: lsyscache.c:1550
#define CharGetDatum(X)
Definition: postgres.h:399
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:462
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:95
#define elog
Definition: elog.h:219
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4736

◆ lookup_agg_function()

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

Definition at line 780 of file pg_aggregate.c.

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

Referenced by AggregateCreate().

785 {
786  Oid fnOid;
787  bool retset;
788  int nvargs;
789  Oid vatype;
790  Oid *true_oid_array;
791  FuncDetailCode fdresult;
792  AclResult aclresult;
793  int i;
794 
795  /*
796  * func_get_detail looks up the function in the catalogs, does
797  * disambiguation for polymorphic functions, handles inheritance, and
798  * returns the funcid and type and set or singleton status of the
799  * function's return value. it also returns the true argument types to
800  * the function.
801  */
802  fdresult = func_get_detail(fnName, NIL, NIL,
803  nargs, input_types, false, false,
804  &fnOid, rettype, &retset,
805  &nvargs, &vatype,
806  &true_oid_array, NULL);
807 
808  /* only valid case is a normal function not returning a set */
809  if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
810  ereport(ERROR,
811  (errcode(ERRCODE_UNDEFINED_FUNCTION),
812  errmsg("function %s does not exist",
813  func_signature_string(fnName, nargs,
814  NIL, input_types))));
815  if (retset)
816  ereport(ERROR,
817  (errcode(ERRCODE_DATATYPE_MISMATCH),
818  errmsg("function %s returns a set",
819  func_signature_string(fnName, nargs,
820  NIL, input_types))));
821 
822  /*
823  * If the agg is declared to take VARIADIC ANY, the underlying functions
824  * had better be declared that way too, else they may receive too many
825  * parameters; but func_get_detail would have been happy with plain ANY.
826  * (Probably nothing very bad would happen, but it wouldn't work as the
827  * user expects.) Other combinations should work without any special
828  * pushups, given that we told func_get_detail not to expand VARIADIC.
829  */
830  if (variadicArgType == ANYOID && vatype != ANYOID)
831  ereport(ERROR,
832  (errcode(ERRCODE_DATATYPE_MISMATCH),
833  errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
834  func_signature_string(fnName, nargs,
835  NIL, input_types))));
836 
837  /*
838  * If there are any polymorphic types involved, enforce consistency, and
839  * possibly refine the result type. It's OK if the result is still
840  * polymorphic at this point, though.
841  */
842  *rettype = enforce_generic_type_consistency(input_types,
843  true_oid_array,
844  nargs,
845  *rettype,
846  true);
847 
848  /*
849  * func_get_detail will find functions requiring run-time argument type
850  * coercion, but nodeAgg.c isn't prepared to deal with that
851  */
852  for (i = 0; i < nargs; i++)
853  {
854  if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
855  ereport(ERROR,
856  (errcode(ERRCODE_DATATYPE_MISMATCH),
857  errmsg("function %s requires run-time type coercion",
858  func_signature_string(fnName, nargs,
859  NIL, true_oid_array))));
860  }
861 
862  /* Check aggregate creator has permission to call the function */
863  aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
864  if (aclresult != ACLCHECK_OK)
865  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
866 
867  return fnOid;
868 }
#define NIL
Definition: pg_list.h:69
Oid GetUserId(void)
Definition: miscinit.c:379
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1397
Oid enforce_generic_type_consistency(Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
FuncDetailCode
Definition: parse_func.h:22
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
bool IsBinaryCoercible(Oid srctype, Oid targettype)
AclResult
Definition: acl.h:178
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:1312
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4648
int i