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(), 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 (no such proc) */
624  NULL, /* probin */
625  NULL, /* prosqlbody */
626  PROKIND_AGGREGATE,
627  false, /* security invoker (currently not
628  * definable for agg) */
629  false, /* isLeakProof */
630  false, /* isStrict (not needed for agg) */
631  PROVOLATILE_IMMUTABLE, /* volatility (not needed
632  * for agg) */
633  proparallel,
634  parameterTypes, /* paramTypes */
635  allParameterTypes, /* allParamTypes */
636  parameterModes, /* parameterModes */
637  parameterNames, /* parameterNames */
638  parameterDefaults, /* parameterDefaults */
639  PointerGetDatum(NULL), /* trftypes */
640  PointerGetDatum(NULL), /* proconfig */
641  InvalidOid, /* no prosupport */
642  1, /* procost */
643  0); /* prorows */
644  procOid = myself.objectId;
645 
646  /*
647  * Okay to create the pg_aggregate entry.
648  */
649  aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
650  tupDesc = aggdesc->rd_att;
651 
652  /* initialize nulls and values */
653  for (i = 0; i < Natts_pg_aggregate; i++)
654  {
655  nulls[i] = false;
656  values[i] = (Datum) NULL;
657  replaces[i] = true;
658  }
659  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
660  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
661  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
662  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
663  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
664  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
665  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
666  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
667  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
668  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
669  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
670  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
671  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
672  values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
673  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
674  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
675  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
676  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
677  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
678  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
679  if (agginitval)
680  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
681  else
682  nulls[Anum_pg_aggregate_agginitval - 1] = true;
683  if (aggminitval)
684  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
685  else
686  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
687 
688  if (replace)
689  oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
690  else
691  oldtup = NULL;
692 
693  if (HeapTupleIsValid(oldtup))
694  {
695  Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
696 
697  /*
698  * If we're replacing an existing entry, we need to validate that
699  * we're not changing anything that would break callers. Specifically
700  * we must not change aggkind or aggnumdirectargs, which affect how an
701  * aggregate call is treated in parse analysis.
702  */
703  if (aggKind != oldagg->aggkind)
704  ereport(ERROR,
705  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
706  errmsg("cannot change routine kind"),
707  (oldagg->aggkind == AGGKIND_NORMAL ?
708  errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
709  oldagg->aggkind == AGGKIND_ORDERED_SET ?
710  errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
711  oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
712  errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
713  0)));
714  if (numDirectArgs != oldagg->aggnumdirectargs)
715  ereport(ERROR,
716  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
717  errmsg("cannot change number of direct arguments of an aggregate function")));
718 
719  replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
720  replaces[Anum_pg_aggregate_aggkind - 1] = false;
721  replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
722 
723  tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
724  CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
725  ReleaseSysCache(oldtup);
726  }
727  else
728  {
729  tup = heap_form_tuple(tupDesc, values, nulls);
730  CatalogTupleInsert(aggdesc, tup);
731  }
732 
733  table_close(aggdesc, RowExclusiveLock);
734 
735  /*
736  * Create dependencies for the aggregate (above and beyond those already
737  * made by ProcedureCreate). Note: we don't need an explicit dependency
738  * on aggTransType since we depend on it indirectly through transfn.
739  * Likewise for aggmTransType using the mtransfn, if it exists.
740  *
741  * If we're replacing an existing definition, ProcedureCreate deleted all
742  * our existing dependencies, so we have to do the same things here either
743  * way.
744  */
745 
746  addrs = new_object_addresses();
747 
748  /* Depends on transition function */
749  ObjectAddressSet(referenced, ProcedureRelationId, transfn);
750  add_exact_object_address(&referenced, addrs);
751 
752  /* Depends on final function, if any */
753  if (OidIsValid(finalfn))
754  {
755  ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
756  add_exact_object_address(&referenced, addrs);
757  }
758 
759  /* Depends on combine function, if any */
760  if (OidIsValid(combinefn))
761  {
762  ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
763  add_exact_object_address(&referenced, addrs);
764  }
765 
766  /* Depends on serialization function, if any */
767  if (OidIsValid(serialfn))
768  {
769  ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
770  add_exact_object_address(&referenced, addrs);
771  }
772 
773  /* Depends on deserialization function, if any */
774  if (OidIsValid(deserialfn))
775  {
776  ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
777  add_exact_object_address(&referenced, addrs);
778  }
779 
780  /* Depends on forward transition function, if any */
781  if (OidIsValid(mtransfn))
782  {
783  ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
784  add_exact_object_address(&referenced, addrs);
785  }
786 
787  /* Depends on inverse transition function, if any */
788  if (OidIsValid(minvtransfn))
789  {
790  ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
791  add_exact_object_address(&referenced, addrs);
792  }
793 
794  /* Depends on final function, if any */
795  if (OidIsValid(mfinalfn))
796  {
797  ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
798  add_exact_object_address(&referenced, addrs);
799  }
800 
801  /* Depends on sort operator, if any */
802  if (OidIsValid(sortop))
803  {
804  ObjectAddressSet(referenced, OperatorRelationId, sortop);
805  add_exact_object_address(&referenced, addrs);
806  }
807 
809  free_object_addresses(addrs);
810  return myself;
811 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
Oid GetUserId(void)
Definition: miscinit.c:478
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1019
#define PointerGetDatum(X)
Definition: postgres.h:600
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2701
#define Int16GetDatum(X)
Definition: postgres.h:495
int errcode(int sqlerrcode)
Definition: elog.c:698
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:2492
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2437
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2732
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3626
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1069
#define FUNC_MAX_ARGS
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:668
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define ACL_USAGE
Definition: parsenodes.h:90
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:826
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
char * NameListToString(List *names)
Definition: namespace.c:3101
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
TupleDesc rd_att
Definition: rel.h:110
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
#define BoolGetDatum(X)
Definition: postgres.h:446
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
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:1732
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:460
static Datum values[MAXATTR]
Definition: bootstrap.c:166
#define Int32GetDatum(X)
Definition: postgres.h:523
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:82
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4811
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
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, Node *prosqlbody, 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:70
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 826 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().

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