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_aggregate_fn.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc_fn.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 48 of file pg_aggregate.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, AGGKIND_HYPOTHETICAL, AGGKIND_IS_ORDERED_SET, AggregateRelationId, Anum_pg_aggregate_aggcombinefn, Anum_pg_aggregate_aggdeserialfn, Anum_pg_aggregate_aggfinalextra, Anum_pg_aggregate_aggfinalfn, Anum_pg_aggregate_aggfinalmodify, Anum_pg_aggregate_aggfnoid, Anum_pg_aggregate_agginitval, Anum_pg_aggregate_aggkind, Anum_pg_aggregate_aggmfinalextra, Anum_pg_aggregate_aggmfinalfn, Anum_pg_aggregate_aggmfinalmodify, Anum_pg_aggregate_aggminitval, Anum_pg_aggregate_aggminvtransfn, Anum_pg_aggregate_aggmtransfn, Anum_pg_aggregate_aggmtransspace, Anum_pg_aggregate_aggmtranstype, Anum_pg_aggregate_aggnumdirectargs, Anum_pg_aggregate_aggserialfn, Anum_pg_aggregate_aggsortop, Anum_pg_aggregate_aggtransfn, Anum_pg_aggregate_aggtransspace, Anum_pg_aggregate_aggtranstype, ANYOID, Assert, BoolGetDatum, BYTEAOID, 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, INTERNALlanguageId, INTERNALOID, InvalidOid, IsBinaryCoercible(), IsPolymorphicType, lookup_agg_function(), LookupOperName(), NameListToString(), Natts_pg_aggregate, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OperatorRelationId, pg_type_aclcheck(), PointerGetDatum, ProcedureCreate(), ProcedureRelationId, PROCOID, PROVOLATILE_IMMUTABLE, RelationData::rd_att, recordDependencyOn(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), values, and oidvector::values.

Referenced by DefineAggregate().

79 {
80  Relation aggdesc;
81  HeapTuple tup;
82  bool nulls[Natts_pg_aggregate];
84  Form_pg_proc proc;
85  Oid transfn;
86  Oid finalfn = InvalidOid; /* can be omitted */
87  Oid combinefn = InvalidOid; /* can be omitted */
88  Oid serialfn = InvalidOid; /* can be omitted */
89  Oid deserialfn = InvalidOid; /* can be omitted */
90  Oid mtransfn = InvalidOid; /* can be omitted */
91  Oid minvtransfn = InvalidOid; /* can be omitted */
92  Oid mfinalfn = InvalidOid; /* can be omitted */
93  Oid sortop = InvalidOid; /* can be omitted */
94  Oid *aggArgTypes = parameterTypes->values;
95  bool hasPolyArg;
96  bool hasInternalArg;
97  bool mtransIsStrict = false;
98  Oid rettype;
99  Oid finaltype;
100  Oid fnArgs[FUNC_MAX_ARGS];
101  int nargs_transfn;
102  int nargs_finalfn;
103  Oid procOid;
104  TupleDesc tupDesc;
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 args 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  /* check for polymorphic and INTERNAL arguments */
134  hasPolyArg = false;
135  hasInternalArg = false;
136  for (i = 0; i < numArgs; i++)
137  {
138  if (IsPolymorphicType(aggArgTypes[i]))
139  hasPolyArg = true;
140  else if (aggArgTypes[i] == INTERNALOID)
141  hasInternalArg = true;
142  }
143 
144  /*
145  * If transtype is polymorphic, must have polymorphic argument also; else
146  * we will have no way to deduce the actual transtype.
147  */
148  if (IsPolymorphicType(aggTransType) && !hasPolyArg)
149  ereport(ERROR,
150  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
151  errmsg("cannot determine transition data type"),
152  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
153 
154  /*
155  * Likewise for moving-aggregate transtype, if any
156  */
157  if (OidIsValid(aggmTransType) &&
158  IsPolymorphicType(aggmTransType) && !hasPolyArg)
159  ereport(ERROR,
160  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
161  errmsg("cannot determine transition data type"),
162  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
163 
164  /*
165  * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
166  * principle we could support regular variadic types, but it would make
167  * things much more complicated because we'd have to assemble the correct
168  * subsets of arguments into array values. Since no standard aggregates
169  * have use for such a case, we aren't bothering for now.
170  */
171  if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
172  variadicArgType != ANYOID)
173  ereport(ERROR,
174  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
175  errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
176 
177  /*
178  * If it's a hypothetical-set aggregate, there must be at least as many
179  * direct arguments as aggregated ones, and the last N direct arguments
180  * must match the aggregated ones in type. (We have to check this again
181  * when the aggregate is called, in case ANY is involved, but it makes
182  * sense to reject the aggregate definition now if the declared arg types
183  * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
184  * indicating that the grammar merged identical VARIADIC entries from both
185  * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
186  * the aggregated side, which is not OK. Otherwise, insist on the last N
187  * parameter types on each side matching exactly.
188  */
189  if (aggKind == AGGKIND_HYPOTHETICAL &&
190  numDirectArgs < numArgs)
191  {
192  int numAggregatedArgs = numArgs - numDirectArgs;
193 
194  if (OidIsValid(variadicArgType) ||
195  numDirectArgs < numAggregatedArgs ||
196  memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
197  aggArgTypes + numDirectArgs,
198  numAggregatedArgs * sizeof(Oid)) != 0)
199  ereport(ERROR,
200  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
201  errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
202  }
203 
204  /*
205  * Find the transfn. For ordinary aggs, it takes the transtype plus all
206  * aggregate arguments. For ordered-set aggs, it takes the transtype plus
207  * all aggregated args, but not direct args. However, we have to treat
208  * specially the case where a trailing VARIADIC item is considered to
209  * cover both direct and aggregated args.
210  */
211  if (AGGKIND_IS_ORDERED_SET(aggKind))
212  {
213  if (numDirectArgs < numArgs)
214  nargs_transfn = numArgs - numDirectArgs + 1;
215  else
216  {
217  /* special case with VARIADIC last arg */
218  Assert(variadicArgType != InvalidOid);
219  nargs_transfn = 2;
220  }
221  fnArgs[0] = aggTransType;
222  memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
223  (nargs_transfn - 1) * sizeof(Oid));
224  }
225  else
226  {
227  nargs_transfn = numArgs + 1;
228  fnArgs[0] = aggTransType;
229  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
230  }
231  transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
232  fnArgs, variadicArgType,
233  &rettype);
234 
235  /*
236  * Return type of transfn (possibly after refinement by
237  * enforce_generic_type_consistency, if transtype isn't polymorphic) must
238  * exactly match declared transtype.
239  *
240  * In the non-polymorphic-transtype case, it might be okay to allow a
241  * rettype that's binary-coercible to transtype, but I'm not quite
242  * convinced that it's either safe or useful. When transtype is
243  * polymorphic we *must* demand exact equality.
244  */
245  if (rettype != aggTransType)
246  ereport(ERROR,
247  (errcode(ERRCODE_DATATYPE_MISMATCH),
248  errmsg("return type of transition function %s is not %s",
249  NameListToString(aggtransfnName),
250  format_type_be(aggTransType))));
251 
252  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
253  if (!HeapTupleIsValid(tup))
254  elog(ERROR, "cache lookup failed for function %u", transfn);
255  proc = (Form_pg_proc) GETSTRUCT(tup);
256 
257  /*
258  * If the transfn is strict and the initval is NULL, make sure first input
259  * type and transtype are the same (or at least binary-compatible), so
260  * that it's OK to use the first input value as the initial transValue.
261  */
262  if (proc->proisstrict && agginitval == NULL)
263  {
264  if (numArgs < 1 ||
265  !IsBinaryCoercible(aggArgTypes[0], aggTransType))
266  ereport(ERROR,
267  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
268  errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
269  }
270 
271  ReleaseSysCache(tup);
272 
273  /* handle moving-aggregate transfn, if supplied */
274  if (aggmtransfnName)
275  {
276  /*
277  * The arguments are the same as for the regular transfn, except that
278  * the transition data type might be different. So re-use the fnArgs
279  * values set up above, except for that one.
280  */
281  Assert(OidIsValid(aggmTransType));
282  fnArgs[0] = aggmTransType;
283 
284  mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
285  fnArgs, variadicArgType,
286  &rettype);
287 
288  /* As above, return type must exactly match declared mtranstype. */
289  if (rettype != aggmTransType)
290  ereport(ERROR,
291  (errcode(ERRCODE_DATATYPE_MISMATCH),
292  errmsg("return type of transition function %s is not %s",
293  NameListToString(aggmtransfnName),
294  format_type_be(aggmTransType))));
295 
296  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
297  if (!HeapTupleIsValid(tup))
298  elog(ERROR, "cache lookup failed for function %u", mtransfn);
299  proc = (Form_pg_proc) GETSTRUCT(tup);
300 
301  /*
302  * If the mtransfn is strict and the minitval is NULL, check first
303  * input type and mtranstype are binary-compatible.
304  */
305  if (proc->proisstrict && aggminitval == NULL)
306  {
307  if (numArgs < 1 ||
308  !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
309  ereport(ERROR,
310  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
311  errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
312  }
313 
314  /* Remember if mtransfn is strict; we may need this below */
315  mtransIsStrict = proc->proisstrict;
316 
317  ReleaseSysCache(tup);
318  }
319 
320  /* handle minvtransfn, if supplied */
321  if (aggminvtransfnName)
322  {
323  /*
324  * This must have the same number of arguments with the same types as
325  * the forward transition function, so just re-use the fnArgs data.
326  */
327  Assert(aggmtransfnName);
328 
329  minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
330  fnArgs, variadicArgType,
331  &rettype);
332 
333  /* As above, return type must exactly match declared mtranstype. */
334  if (rettype != aggmTransType)
335  ereport(ERROR,
336  (errcode(ERRCODE_DATATYPE_MISMATCH),
337  errmsg("return type of inverse transition function %s is not %s",
338  NameListToString(aggminvtransfnName),
339  format_type_be(aggmTransType))));
340 
341  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
342  if (!HeapTupleIsValid(tup))
343  elog(ERROR, "cache lookup failed for function %u", minvtransfn);
344  proc = (Form_pg_proc) GETSTRUCT(tup);
345 
346  /*
347  * We require the strictness settings of the forward and inverse
348  * transition functions to agree. This saves having to handle
349  * assorted special cases at execution time.
350  */
351  if (proc->proisstrict != mtransIsStrict)
352  ereport(ERROR,
353  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
354  errmsg("strictness of aggregate's forward and inverse transition functions must match")));
355 
356  ReleaseSysCache(tup);
357  }
358 
359  /* handle finalfn, if supplied */
360  if (aggfinalfnName)
361  {
362  /*
363  * If finalfnExtraArgs is specified, the transfn takes the transtype
364  * plus all args; otherwise, it just takes the transtype plus any
365  * direct args. (Non-direct args are useless at runtime, and are
366  * actually passed as NULLs, but we may need them in the function
367  * signature to allow resolution of a polymorphic agg's result type.)
368  */
369  Oid ffnVariadicArgType = variadicArgType;
370 
371  fnArgs[0] = aggTransType;
372  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
373  if (finalfnExtraArgs)
374  nargs_finalfn = numArgs + 1;
375  else
376  {
377  nargs_finalfn = numDirectArgs + 1;
378  if (numDirectArgs < numArgs)
379  {
380  /* variadic argument doesn't affect finalfn */
381  ffnVariadicArgType = InvalidOid;
382  }
383  }
384 
385  finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
386  fnArgs, ffnVariadicArgType,
387  &finaltype);
388 
389  /*
390  * When finalfnExtraArgs is specified, the finalfn will certainly be
391  * passed at least one null argument, so complain if it's strict.
392  * Nothing bad would happen at runtime (you'd just get a null result),
393  * but it's surely not what the user wants, so let's complain now.
394  */
395  if (finalfnExtraArgs && func_strict(finalfn))
396  ereport(ERROR,
397  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398  errmsg("final function with extra arguments must not be declared STRICT")));
399  }
400  else
401  {
402  /*
403  * If no finalfn, aggregate result type is type of the state value
404  */
405  finaltype = aggTransType;
406  }
407  Assert(OidIsValid(finaltype));
408 
409  /* handle the combinefn, if supplied */
410  if (aggcombinefnName)
411  {
412  Oid combineType;
413 
414  /*
415  * Combine function must have 2 argument, each of which is the trans
416  * type
417  */
418  fnArgs[0] = aggTransType;
419  fnArgs[1] = aggTransType;
420 
421  combinefn = lookup_agg_function(aggcombinefnName, 2, fnArgs,
422  variadicArgType, &combineType);
423 
424  /* Ensure the return type matches the aggregates trans type */
425  if (combineType != aggTransType)
426  ereport(ERROR,
427  (errcode(ERRCODE_DATATYPE_MISMATCH),
428  errmsg("return type of combine function %s is not %s",
429  NameListToString(aggcombinefnName),
430  format_type_be(aggTransType))));
431 
432  /*
433  * A combine function to combine INTERNAL states must accept nulls and
434  * ensure that the returned state is in the correct memory context.
435  */
436  if (aggTransType == INTERNALOID && func_strict(combinefn))
437  ereport(ERROR,
438  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
439  errmsg("combine function with transition type %s must not be declared STRICT",
440  format_type_be(aggTransType))));
441 
442  }
443 
444  /*
445  * Validate the serialization function, if present.
446  */
447  if (aggserialfnName)
448  {
449  fnArgs[0] = INTERNALOID;
450 
451  serialfn = lookup_agg_function(aggserialfnName, 1,
452  fnArgs, variadicArgType,
453  &rettype);
454 
455  if (rettype != BYTEAOID)
456  ereport(ERROR,
457  (errcode(ERRCODE_DATATYPE_MISMATCH),
458  errmsg("return type of serialization function %s is not %s",
459  NameListToString(aggserialfnName),
461  }
462 
463  /*
464  * Validate the deserialization function, if present.
465  */
466  if (aggdeserialfnName)
467  {
468  fnArgs[0] = BYTEAOID;
469  fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
470 
471  deserialfn = lookup_agg_function(aggdeserialfnName, 2,
472  fnArgs, variadicArgType,
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),
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  if (IsPolymorphicType(finaltype) && !hasPolyArg)
492  ereport(ERROR,
493  (errcode(ERRCODE_DATATYPE_MISMATCH),
494  errmsg("cannot determine result data type"),
495  errdetail("An aggregate returning a polymorphic type "
496  "must have at least one polymorphic argument.")));
497 
498  /*
499  * Also, the return type can't be INTERNAL unless there's at least one
500  * INTERNAL argument. This is the same type-safety restriction we enforce
501  * for regular functions, but at the level of aggregates. We must test
502  * this explicitly because we allow INTERNAL as the transtype.
503  */
504  if (finaltype == INTERNALOID && !hasInternalArg)
505  ereport(ERROR,
506  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
507  errmsg("unsafe use of pseudo-type \"internal\""),
508  errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
509 
510  /*
511  * If a moving-aggregate implementation is supplied, look up its finalfn
512  * if any, and check that the implied aggregate result type matches the
513  * plain implementation.
514  */
515  if (OidIsValid(aggmTransType))
516  {
517  /* handle finalfn, if supplied */
518  if (aggmfinalfnName)
519  {
520  /*
521  * The arguments are figured the same way as for the regular
522  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
523  */
524  Oid ffnVariadicArgType = variadicArgType;
525 
526  fnArgs[0] = aggmTransType;
527  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
528  if (mfinalfnExtraArgs)
529  nargs_finalfn = numArgs + 1;
530  else
531  {
532  nargs_finalfn = numDirectArgs + 1;
533  if (numDirectArgs < numArgs)
534  {
535  /* variadic argument doesn't affect finalfn */
536  ffnVariadicArgType = InvalidOid;
537  }
538  }
539 
540  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
541  fnArgs, ffnVariadicArgType,
542  &rettype);
543 
544  /* As above, check strictness if mfinalfnExtraArgs is given */
545  if (mfinalfnExtraArgs && func_strict(mfinalfn))
546  ereport(ERROR,
547  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
548  errmsg("final function with extra arguments must not be declared STRICT")));
549  }
550  else
551  {
552  /*
553  * If no finalfn, aggregate result type is type of the state value
554  */
555  rettype = aggmTransType;
556  }
557  Assert(OidIsValid(rettype));
558  if (rettype != finaltype)
559  ereport(ERROR,
560  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
561  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
562  format_type_be(aggmTransType),
563  format_type_be(aggTransType))));
564  }
565 
566  /* handle sortop, if supplied */
567  if (aggsortopName)
568  {
569  if (numArgs != 1)
570  ereport(ERROR,
571  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572  errmsg("sort operator can only be specified for single-argument aggregates")));
573  sortop = LookupOperName(NULL, aggsortopName,
574  aggArgTypes[0], aggArgTypes[0],
575  false, -1);
576  }
577 
578  /*
579  * permission checks on used types
580  */
581  for (i = 0; i < numArgs; i++)
582  {
583  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
584  if (aclresult != ACLCHECK_OK)
585  aclcheck_error_type(aclresult, aggArgTypes[i]);
586  }
587 
588  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
589  if (aclresult != ACLCHECK_OK)
590  aclcheck_error_type(aclresult, aggTransType);
591 
592  if (OidIsValid(aggmTransType))
593  {
594  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
595  if (aclresult != ACLCHECK_OK)
596  aclcheck_error_type(aclresult, aggmTransType);
597  }
598 
599  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
600  if (aclresult != ACLCHECK_OK)
601  aclcheck_error_type(aclresult, finaltype);
602 
603 
604  /*
605  * Everything looks okay. Try to create the pg_proc entry for the
606  * aggregate. (This could fail if there's already a conflicting entry.)
607  */
608 
609  myself = ProcedureCreate(aggName,
610  aggNamespace,
611  false, /* no replacement */
612  false, /* doesn't return a set */
613  finaltype, /* returnType */
614  GetUserId(), /* proowner */
615  INTERNALlanguageId, /* languageObjectId */
616  InvalidOid, /* no validator */
617  "aggregate_dummy", /* placeholder proc */
618  NULL, /* probin */
619  true, /* isAgg */
620  false, /* isWindowFunc */
621  false, /* security invoker (currently not
622  * definable for agg) */
623  false, /* isLeakProof */
624  false, /* isStrict (not needed for agg) */
625  PROVOLATILE_IMMUTABLE, /* volatility (not needed
626  * for agg) */
627  proparallel,
628  parameterTypes, /* paramTypes */
629  allParameterTypes, /* allParamTypes */
630  parameterModes, /* parameterModes */
631  parameterNames, /* parameterNames */
632  parameterDefaults, /* parameterDefaults */
633  PointerGetDatum(NULL), /* trftypes */
634  PointerGetDatum(NULL), /* proconfig */
635  1, /* procost */
636  0); /* prorows */
637  procOid = myself.objectId;
638 
639  /*
640  * Okay to create the pg_aggregate entry.
641  */
642 
643  /* initialize nulls and values */
644  for (i = 0; i < Natts_pg_aggregate; i++)
645  {
646  nulls[i] = false;
647  values[i] = (Datum) NULL;
648  }
649  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
650  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
651  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
652  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
653  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
654  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
655  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
656  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
657  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
658  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
659  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
660  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
661  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
662  values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
663  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
664  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
665  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
666  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
667  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
668  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
669  if (agginitval)
670  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
671  else
672  nulls[Anum_pg_aggregate_agginitval - 1] = true;
673  if (aggminitval)
674  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
675  else
676  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
677 
679  tupDesc = aggdesc->rd_att;
680 
681  tup = heap_form_tuple(tupDesc, values, nulls);
682  CatalogTupleInsert(aggdesc, tup);
683 
684  heap_close(aggdesc, RowExclusiveLock);
685 
686  /*
687  * Create dependencies for the aggregate (above and beyond those already
688  * made by ProcedureCreate). Note: we don't need an explicit dependency
689  * on aggTransType since we depend on it indirectly through transfn.
690  * Likewise for aggmTransType using the mtransfunc, if it exists.
691  */
692 
693  /* Depends on transition function */
694  referenced.classId = ProcedureRelationId;
695  referenced.objectId = transfn;
696  referenced.objectSubId = 0;
697  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
698 
699  /* Depends on final function, if any */
700  if (OidIsValid(finalfn))
701  {
702  referenced.classId = ProcedureRelationId;
703  referenced.objectId = finalfn;
704  referenced.objectSubId = 0;
705  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
706  }
707 
708  /* Depends on combine function, if any */
709  if (OidIsValid(combinefn))
710  {
711  referenced.classId = ProcedureRelationId;
712  referenced.objectId = combinefn;
713  referenced.objectSubId = 0;
714  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
715  }
716 
717  /* Depends on serialization function, if any */
718  if (OidIsValid(serialfn))
719  {
720  referenced.classId = ProcedureRelationId;
721  referenced.objectId = serialfn;
722  referenced.objectSubId = 0;
723  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
724  }
725 
726  /* Depends on deserialization function, if any */
727  if (OidIsValid(deserialfn))
728  {
729  referenced.classId = ProcedureRelationId;
730  referenced.objectId = deserialfn;
731  referenced.objectSubId = 0;
732  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
733  }
734 
735  /* Depends on forward transition function, if any */
736  if (OidIsValid(mtransfn))
737  {
738  referenced.classId = ProcedureRelationId;
739  referenced.objectId = mtransfn;
740  referenced.objectSubId = 0;
741  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
742  }
743 
744  /* Depends on inverse transition function, if any */
745  if (OidIsValid(minvtransfn))
746  {
747  referenced.classId = ProcedureRelationId;
748  referenced.objectId = minvtransfn;
749  referenced.objectSubId = 0;
750  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
751  }
752 
753  /* Depends on final function, if any */
754  if (OidIsValid(mfinalfn))
755  {
756  referenced.classId = ProcedureRelationId;
757  referenced.objectId = mfinalfn;
758  referenced.objectSubId = 0;
759  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
760  }
761 
762  /* Depends on sort operator, if any */
763  if (OidIsValid(sortop))
764  {
765  referenced.classId = OperatorRelationId;
766  referenced.objectId = sortop;
767  referenced.objectSubId = 0;
768  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
769  }
770 
771  return myself;
772 }
#define Anum_pg_aggregate_aggfinalmodify
Definition: pg_aggregate.h:110
#define OperatorRelationId
Definition: pg_operator.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define PROVOLATILE_IMMUTABLE
Definition: pg_proc.h:5537
#define Anum_pg_aggregate_aggtransspace
Definition: pg_aggregate.h:114
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:117
#define INTERNALlanguageId
Definition: pg_language.h:74
Oid GetUserId(void)
Definition: miscinit.c:284
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:106
#define ProcedureRelationId
Definition: pg_proc.h:33
#define Anum_pg_aggregate_aggdeserialfn
Definition: pg_aggregate.h:104
#define Int16GetDatum(X)
Definition: postgres.h:457
#define Anum_pg_aggregate_aggtransfn
Definition: pg_aggregate.h:100
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:695
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
#define AggregateRelationId
Definition: pg_aggregate.h:53
#define Anum_pg_aggregate_aggserialfn
Definition: pg_aggregate.h:103
#define FUNC_MAX_ARGS
#define AGGKIND_IS_ORDERED_SET(kind)
Definition: pg_aggregate.h:133
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define IsPolymorphicType(typid)
Definition: pg_type.h:745
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define Anum_pg_aggregate_aggfnoid
Definition: pg_aggregate.h:97
#define Anum_pg_aggregate_aggcombinefn
Definition: pg_aggregate.h:102
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:534
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ANYOID
Definition: pg_type.h:686
#define Anum_pg_aggregate_aggmfinalmodify
Definition: pg_aggregate.h:111
#define ACL_USAGE
Definition: parsenodes.h:80
#define Anum_pg_aggregate_aggmtranstype
Definition: pg_aggregate.h:115
#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:783
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define Natts_pg_aggregate
Definition: pg_aggregate.h:96
#define Anum_pg_aggregate_aggmfinalextra
Definition: pg_aggregate.h:109
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3063
#define Anum_pg_aggregate_aggsortop
Definition: pg_aggregate.h:112
#define Anum_pg_aggregate_aggkind
Definition: pg_aggregate.h:98
#define Anum_pg_aggregate_aggminitval
Definition: pg_aggregate.h:118
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define Anum_pg_aggregate_aggfinalextra
Definition: pg_aggregate.h:108
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
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:698
#define Anum_pg_aggregate_aggmtransfn
Definition: pg_aggregate.h:105
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_aggregate_aggfinalfn
Definition: pg_aggregate.h:101
#define Assert(condition)
Definition: c.h:670
bool func_strict(Oid funcid)
Definition: lsyscache.c:1565
#define CharGetDatum(X)
Definition: postgres.h:422
#define BYTEAOID
Definition: pg_type.h:292
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:485
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define Anum_pg_aggregate_aggnumdirectargs
Definition: pg_aggregate.h:99
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
#define Anum_pg_aggregate_aggmtransspace
Definition: pg_aggregate.h:116
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4534
#define AGGKIND_HYPOTHETICAL
Definition: pg_aggregate.h:130
#define Anum_pg_aggregate_aggmfinalfn
Definition: pg_aggregate.h:107
#define Anum_pg_aggregate_aggtranstype
Definition: pg_aggregate.h:113

◆ lookup_agg_function()

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

Definition at line 783 of file pg_aggregate.c.

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

Referenced by AggregateCreate().

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