PostgreSQL Source Code  git master
pg_aggregate.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.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, bool replace, char aggKind, int numArgs, int numDirectArgs, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Oid variadicArgType, List *aggtransfnName, List *aggfinalfnName, List *aggcombinefnName, List *aggserialfnName, List *aggdeserialfnName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, char finalfnModify, char mfinalfnModify, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
 

Function Documentation

◆ AggregateCreate()

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

Definition at line 46 of file pg_aggregate.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, add_exact_object_address(), AGGFNOID, Assert, BoolGetDatum, CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, check_valid_internal_signature(), check_valid_polymorphic_signature(), CStringGetTextDatum, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_WRONG_OBJECT_TYPE, errdetail(), errdetail_internal(), errmsg(), errmsg_plural(), ERROR, format_type_be(), free_object_addresses(), FUNC_MAX_ARGS, func_strict(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, Int16GetDatum, Int32GetDatum, InvalidOid, IsBinaryCoercible(), lookup_agg_function(), LookupOperName(), NameListToString(), new_object_addresses(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, pg_type_aclcheck(), PointerGetDatum, ProcedureCreate(), PROCOID, RelationData::rd_att, record_object_address_dependencies(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), table_open(), values, and oidvector::values.

Referenced by DefineAggregate().

78 {
79  Relation aggdesc;
80  HeapTuple tup;
81  HeapTuple oldtup;
82  bool nulls[Natts_pg_aggregate];
83  Datum values[Natts_pg_aggregate];
84  bool replaces[Natts_pg_aggregate];
85  Form_pg_proc proc;
86  Oid transfn;
87  Oid finalfn = InvalidOid; /* can be omitted */
88  Oid combinefn = InvalidOid; /* can be omitted */
89  Oid serialfn = InvalidOid; /* can be omitted */
90  Oid deserialfn = InvalidOid; /* can be omitted */
91  Oid mtransfn = InvalidOid; /* can be omitted */
92  Oid minvtransfn = InvalidOid; /* can be omitted */
93  Oid mfinalfn = InvalidOid; /* can be omitted */
94  Oid sortop = InvalidOid; /* can be omitted */
95  Oid *aggArgTypes = parameterTypes->values;
96  bool mtransIsStrict = false;
97  Oid rettype;
98  Oid finaltype;
99  Oid fnArgs[FUNC_MAX_ARGS];
100  int nargs_transfn;
101  int nargs_finalfn;
102  Oid procOid;
103  TupleDesc tupDesc;
104  char *detailmsg;
105  int i;
106  ObjectAddress myself,
107  referenced;
108  ObjectAddresses *addrs;
109  AclResult aclresult;
110 
111  /* sanity checks (caller should have caught these) */
112  if (!aggName)
113  elog(ERROR, "no aggregate name supplied");
114 
115  if (!aggtransfnName)
116  elog(ERROR, "aggregate must have a transition function");
117 
118  if (numDirectArgs < 0 || numDirectArgs > numArgs)
119  elog(ERROR, "incorrect number of direct arguments for aggregate");
120 
121  /*
122  * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
123  * and/or finalfn will be unrepresentable in pg_proc. We must check now
124  * to protect fixed-size arrays here and possibly in called functions.
125  */
126  if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
127  ereport(ERROR,
128  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
129  errmsg_plural("aggregates cannot have more than %d argument",
130  "aggregates cannot have more than %d arguments",
131  FUNC_MAX_ARGS - 1,
132  FUNC_MAX_ARGS - 1)));
133 
134  /*
135  * If transtype is polymorphic, must have polymorphic argument also; else
136  * we will have no way to deduce the actual transtype.
137  */
138  detailmsg = check_valid_polymorphic_signature(aggTransType,
139  aggArgTypes,
140  numArgs);
141  if (detailmsg)
142  ereport(ERROR,
143  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
144  errmsg("cannot determine transition data type"),
145  errdetail_internal("%s", detailmsg)));
146 
147  /*
148  * Likewise for moving-aggregate transtype, if any
149  */
150  if (OidIsValid(aggmTransType))
151  {
152  detailmsg = check_valid_polymorphic_signature(aggmTransType,
153  aggArgTypes,
154  numArgs);
155  if (detailmsg)
156  ereport(ERROR,
157  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158  errmsg("cannot determine transition data type"),
159  errdetail_internal("%s", detailmsg)));
160  }
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 arguments, each of which is the trans
414  * type. VARIADIC doesn't affect it.
415  */
416  fnArgs[0] = aggTransType;
417  fnArgs[1] = aggTransType;
418 
419  combinefn = lookup_agg_function(aggcombinefnName, 2,
420  fnArgs, InvalidOid,
421  &combineType);
422 
423  /* Ensure the return type matches the aggregate's trans type */
424  if (combineType != aggTransType)
425  ereport(ERROR,
426  (errcode(ERRCODE_DATATYPE_MISMATCH),
427  errmsg("return type of combine function %s is not %s",
428  NameListToString(aggcombinefnName),
429  format_type_be(aggTransType))));
430 
431  /*
432  * A combine function to combine INTERNAL states must accept nulls and
433  * ensure that the returned state is in the correct memory context. We
434  * cannot directly check the latter, but we can check the former.
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  * Validate the serialization function, if present.
445  */
446  if (aggserialfnName)
447  {
448  /* signature is always serialize(internal) returns bytea */
449  fnArgs[0] = INTERNALOID;
450 
451  serialfn = lookup_agg_function(aggserialfnName, 1,
452  fnArgs, InvalidOid,
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),
460  format_type_be(BYTEAOID))));
461  }
462 
463  /*
464  * Validate the deserialization function, if present.
465  */
466  if (aggdeserialfnName)
467  {
468  /* signature is always deserialize(bytea, internal) returns internal */
469  fnArgs[0] = BYTEAOID;
470  fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
471 
472  deserialfn = lookup_agg_function(aggdeserialfnName, 2,
473  fnArgs, InvalidOid,
474  &rettype);
475 
476  if (rettype != INTERNALOID)
477  ereport(ERROR,
478  (errcode(ERRCODE_DATATYPE_MISMATCH),
479  errmsg("return type of deserialization function %s is not %s",
480  NameListToString(aggdeserialfnName),
481  format_type_be(INTERNALOID))));
482  }
483 
484  /*
485  * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
486  * be polymorphic also, else parser will fail to deduce result type.
487  * (Note: given the previous test on transtype and inputs, this cannot
488  * happen, unless someone has snuck a finalfn definition into the catalogs
489  * that itself violates the rule against polymorphic result with no
490  * polymorphic input.)
491  */
492  detailmsg = check_valid_polymorphic_signature(finaltype,
493  aggArgTypes,
494  numArgs);
495  if (detailmsg)
496  ereport(ERROR,
497  (errcode(ERRCODE_DATATYPE_MISMATCH),
498  errmsg("cannot determine result data type"),
499  errdetail_internal("%s", detailmsg)));
500 
501  /*
502  * Also, the return type can't be INTERNAL unless there's at least one
503  * INTERNAL argument. This is the same type-safety restriction we enforce
504  * for regular functions, but at the level of aggregates. We must test
505  * this explicitly because we allow INTERNAL as the transtype.
506  */
507  detailmsg = check_valid_internal_signature(finaltype,
508  aggArgTypes,
509  numArgs);
510  if (detailmsg)
511  ereport(ERROR,
512  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
513  errmsg("unsafe use of pseudo-type \"internal\""),
514  errdetail_internal("%s", detailmsg)));
515 
516  /*
517  * If a moving-aggregate implementation is supplied, look up its finalfn
518  * if any, and check that the implied aggregate result type matches the
519  * plain implementation.
520  */
521  if (OidIsValid(aggmTransType))
522  {
523  /* handle finalfn, if supplied */
524  if (aggmfinalfnName)
525  {
526  /*
527  * The arguments are figured the same way as for the regular
528  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
529  */
530  Oid ffnVariadicArgType = variadicArgType;
531 
532  fnArgs[0] = aggmTransType;
533  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
534  if (mfinalfnExtraArgs)
535  nargs_finalfn = numArgs + 1;
536  else
537  {
538  nargs_finalfn = numDirectArgs + 1;
539  if (numDirectArgs < numArgs)
540  {
541  /* variadic argument doesn't affect finalfn */
542  ffnVariadicArgType = InvalidOid;
543  }
544  }
545 
546  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
547  fnArgs, ffnVariadicArgType,
548  &rettype);
549 
550  /* As above, check strictness if mfinalfnExtraArgs is given */
551  if (mfinalfnExtraArgs && func_strict(mfinalfn))
552  ereport(ERROR,
553  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
554  errmsg("final function with extra arguments must not be declared STRICT")));
555  }
556  else
557  {
558  /*
559  * If no finalfn, aggregate result type is type of the state value
560  */
561  rettype = aggmTransType;
562  }
563  Assert(OidIsValid(rettype));
564  if (rettype != finaltype)
565  ereport(ERROR,
566  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
567  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
568  format_type_be(rettype),
569  format_type_be(finaltype))));
570  }
571 
572  /* handle sortop, if supplied */
573  if (aggsortopName)
574  {
575  if (numArgs != 1)
576  ereport(ERROR,
577  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
578  errmsg("sort operator can only be specified for single-argument aggregates")));
579  sortop = LookupOperName(NULL, aggsortopName,
580  aggArgTypes[0], aggArgTypes[0],
581  false, -1);
582  }
583 
584  /*
585  * permission checks on used types
586  */
587  for (i = 0; i < numArgs; i++)
588  {
589  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
590  if (aclresult != ACLCHECK_OK)
591  aclcheck_error_type(aclresult, aggArgTypes[i]);
592  }
593 
594  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
595  if (aclresult != ACLCHECK_OK)
596  aclcheck_error_type(aclresult, aggTransType);
597 
598  if (OidIsValid(aggmTransType))
599  {
600  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
601  if (aclresult != ACLCHECK_OK)
602  aclcheck_error_type(aclresult, aggmTransType);
603  }
604 
605  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
606  if (aclresult != ACLCHECK_OK)
607  aclcheck_error_type(aclresult, finaltype);
608 
609 
610  /*
611  * Everything looks okay. Try to create the pg_proc entry for the
612  * aggregate. (This could fail if there's already a conflicting entry.)
613  */
614 
615  myself = ProcedureCreate(aggName,
616  aggNamespace,
617  replace, /* maybe replacement */
618  false, /* doesn't return a set */
619  finaltype, /* returnType */
620  GetUserId(), /* proowner */
621  INTERNALlanguageId, /* languageObjectId */
622  InvalidOid, /* no validator */
623  "aggregate_dummy", /* placeholder proc */
624  NULL, /* probin */
625  PROKIND_AGGREGATE,
626  false, /* security invoker (currently not
627  * definable for agg) */
628  false, /* isLeakProof */
629  false, /* isStrict (not needed for agg) */
630  PROVOLATILE_IMMUTABLE, /* volatility (not needed
631  * for agg) */
632  proparallel,
633  parameterTypes, /* paramTypes */
634  allParameterTypes, /* allParamTypes */
635  parameterModes, /* parameterModes */
636  parameterNames, /* parameterNames */
637  parameterDefaults, /* parameterDefaults */
638  PointerGetDatum(NULL), /* trftypes */
639  PointerGetDatum(NULL), /* proconfig */
640  InvalidOid, /* no prosupport */
641  1, /* procost */
642  0); /* prorows */
643  procOid = myself.objectId;
644 
645  /*
646  * Okay to create the pg_aggregate entry.
647  */
648  aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
649  tupDesc = aggdesc->rd_att;
650 
651  /* initialize nulls and values */
652  for (i = 0; i < Natts_pg_aggregate; i++)
653  {
654  nulls[i] = false;
655  values[i] = (Datum) NULL;
656  replaces[i] = true;
657  }
658  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
659  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
660  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
661  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
662  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
663  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
664  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
665  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
666  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
667  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
668  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
669  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
670  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
671  values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
672  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
673  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
674  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
675  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
676  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
677  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
678  if (agginitval)
679  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
680  else
681  nulls[Anum_pg_aggregate_agginitval - 1] = true;
682  if (aggminitval)
683  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
684  else
685  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
686 
687  if (replace)
688  oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
689  else
690  oldtup = NULL;
691 
692  if (HeapTupleIsValid(oldtup))
693  {
694  Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
695 
696  /*
697  * If we're replacing an existing entry, we need to validate that
698  * we're not changing anything that would break callers. Specifically
699  * we must not change aggkind or aggnumdirectargs, which affect how an
700  * aggregate call is treated in parse analysis.
701  */
702  if (aggKind != oldagg->aggkind)
703  ereport(ERROR,
705  errmsg("cannot change routine kind"),
706  (oldagg->aggkind == AGGKIND_NORMAL ?
707  errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
708  oldagg->aggkind == AGGKIND_ORDERED_SET ?
709  errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
710  oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
711  errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
712  0)));
713  if (numDirectArgs != oldagg->aggnumdirectargs)
714  ereport(ERROR,
715  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
716  errmsg("cannot change number of direct arguments of an aggregate function")));
717 
718  replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
719  replaces[Anum_pg_aggregate_aggkind - 1] = false;
720  replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
721 
722  tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
723  CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
724  ReleaseSysCache(oldtup);
725  }
726  else
727  {
728  tup = heap_form_tuple(tupDesc, values, nulls);
729  CatalogTupleInsert(aggdesc, tup);
730  }
731 
732  table_close(aggdesc, RowExclusiveLock);
733 
734  /*
735  * Create dependencies for the aggregate (above and beyond those already
736  * made by ProcedureCreate). Note: we don't need an explicit dependency
737  * on aggTransType since we depend on it indirectly through transfn.
738  * Likewise for aggmTransType using the mtransfn, if it exists.
739  *
740  * If we're replacing an existing definition, ProcedureCreate deleted all
741  * our existing dependencies, so we have to do the same things here either
742  * way.
743  */
744 
745  addrs = new_object_addresses();
746 
747  /* Depends on transition function */
748  ObjectAddressSet(referenced, ProcedureRelationId, transfn);
749  add_exact_object_address(&referenced, addrs);
750 
751  /* Depends on final function, if any */
752  if (OidIsValid(finalfn))
753  {
754  ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
755  add_exact_object_address(&referenced, addrs);
756  }
757 
758  /* Depends on combine function, if any */
759  if (OidIsValid(combinefn))
760  {
761  ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
762  add_exact_object_address(&referenced, addrs);
763  }
764 
765  /* Depends on serialization function, if any */
766  if (OidIsValid(serialfn))
767  {
768  ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
769  add_exact_object_address(&referenced, addrs);
770  }
771 
772  /* Depends on deserialization function, if any */
773  if (OidIsValid(deserialfn))
774  {
775  ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
776  add_exact_object_address(&referenced, addrs);
777  }
778 
779  /* Depends on forward transition function, if any */
780  if (OidIsValid(mtransfn))
781  {
782  ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
783  add_exact_object_address(&referenced, addrs);
784  }
785 
786  /* Depends on inverse transition function, if any */
787  if (OidIsValid(minvtransfn))
788  {
789  ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
790  add_exact_object_address(&referenced, addrs);
791  }
792 
793  /* Depends on final function, if any */
794  if (OidIsValid(mfinalfn))
795  {
796  ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
797  add_exact_object_address(&referenced, addrs);
798  }
799 
800  /* Depends on sort operator, if any */
801  if (OidIsValid(sortop))
802  {
803  ObjectAddressSet(referenced, OperatorRelationId, sortop);
804  add_exact_object_address(&referenced, addrs);
805  }
806 
808  free_object_addresses(addrs);
809  return myself;
810 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
Oid GetUserId(void)
Definition: miscinit.c:476
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:931
#define PointerGetDatum(X)
Definition: postgres.h:556
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2676
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:69
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:101
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2467
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2412
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2707
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
int errdetail_internal(const char *fmt,...)
Definition: elog.c:981
#define FUNC_MAX_ARGS
#define ERRCODE_WRONG_OBJECT_TYPE
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:610
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:954
#define ACL_USAGE
Definition: parsenodes.h:82
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:825
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3101
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
TupleDesc rd_att
Definition: rel.h:110
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:746
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
bool func_strict(Oid funcid)
Definition: lsyscache.c:1673
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define elog(elevel,...)
Definition: elog.h:214
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:86
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4675
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221

◆ lookup_agg_function()

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

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

830 {
831  Oid fnOid;
832  bool retset;
833  int nvargs;
834  Oid vatype;
835  Oid *true_oid_array;
836  FuncDetailCode fdresult;
837  AclResult aclresult;
838  int i;
839 
840  /*
841  * func_get_detail looks up the function in the catalogs, does
842  * disambiguation for polymorphic functions, handles inheritance, and
843  * returns the funcid and type and set or singleton status of the
844  * function's return value. it also returns the true argument types to
845  * the function.
846  */
847  fdresult = func_get_detail(fnName, NIL, NIL,
848  nargs, input_types, false, false,
849  &fnOid, rettype, &retset,
850  &nvargs, &vatype,
851  &true_oid_array, NULL);
852 
853  /* only valid case is a normal function not returning a set */
854  if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
855  ereport(ERROR,
856  (errcode(ERRCODE_UNDEFINED_FUNCTION),
857  errmsg("function %s does not exist",
858  func_signature_string(fnName, nargs,
859  NIL, input_types))));
860  if (retset)
861  ereport(ERROR,
862  (errcode(ERRCODE_DATATYPE_MISMATCH),
863  errmsg("function %s returns a set",
864  func_signature_string(fnName, nargs,
865  NIL, input_types))));
866 
867  /*
868  * If the agg is declared to take VARIADIC ANY, the underlying functions
869  * had better be declared that way too, else they may receive too many
870  * parameters; but func_get_detail would have been happy with plain ANY.
871  * (Probably nothing very bad would happen, but it wouldn't work as the
872  * user expects.) Other combinations should work without any special
873  * pushups, given that we told func_get_detail not to expand VARIADIC.
874  */
875  if (variadicArgType == ANYOID && vatype != ANYOID)
876  ereport(ERROR,
877  (errcode(ERRCODE_DATATYPE_MISMATCH),
878  errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
879  func_signature_string(fnName, nargs,
880  NIL, input_types))));
881 
882  /*
883  * If there are any polymorphic types involved, enforce consistency, and
884  * possibly refine the result type. It's OK if the result is still
885  * polymorphic at this point, though.
886  */
887  *rettype = enforce_generic_type_consistency(input_types,
888  true_oid_array,
889  nargs,
890  *rettype,
891  true);
892 
893  /*
894  * func_get_detail will find functions requiring run-time argument type
895  * coercion, but nodeAgg.c isn't prepared to deal with that
896  */
897  for (i = 0; i < nargs; i++)
898  {
899  if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
900  ereport(ERROR,
901  (errcode(ERRCODE_DATATYPE_MISMATCH),
902  errmsg("function %s requires run-time type coercion",
903  func_signature_string(fnName, nargs,
904  NIL, true_oid_array))));
905  }
906 
907  /* Check aggregate creator has permission to call the function */
908  aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
909  if (aclresult != ACLCHECK_OK)
910  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
911 
912  return fnOid;
913 }
#define NIL
Definition: pg_list.h:65
Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid *declared_arg_types, int nargs, Oid rettype, bool allow_poly)
Oid GetUserId(void)
Definition: miscinit.c:476
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
FuncDetailCode
Definition: parse_func.h:22
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2019
bool IsBinaryCoercible(Oid srctype, Oid targettype)
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:144
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1382
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
int i