PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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_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, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
 

Function Documentation

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

Definition at line 47 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_aggfnoid, Anum_pg_aggregate_agginitval, Anum_pg_aggregate_aggkind, Anum_pg_aggregate_aggmfinalextra, Anum_pg_aggregate_aggmfinalfn, 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().

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

Definition at line 778 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().

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