PostgreSQL Source Code  git master
pg_aggregate.h File Reference
#include "catalog/genbki.h"
#include "catalog/pg_aggregate_d.h"
#include "catalog/objectaddress.h"
#include "nodes/pg_list.h"
Include dependency graph for pg_aggregate.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef FormData_pg_aggregateForm_pg_aggregate
 

Functions

 CATALOG (pg_aggregate, 2600, AggregateRelationId)
 
 DECLARE_TOAST (pg_aggregate, 4159, 4160)
 
 DECLARE_UNIQUE_INDEX_PKEY (pg_aggregate_fnoid_index, 2650, AggregateFnoidIndexId, pg_aggregate, btree(aggfnoid oid_ops))
 
 MAKE_SYSCACHE (AGGFNOID, pg_aggregate_fnoid_index, 16)
 
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)
 

Variables

 FormData_pg_aggregate
 

Typedef Documentation

◆ Form_pg_aggregate

Definition at line 109 of file pg_aggregate.h.

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.

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 = object_aclcheck(TypeRelationId, aggArgTypes[i], GetUserId(), ACL_USAGE);
590  if (aclresult != ACLCHECK_OK)
591  aclcheck_error_type(aclresult, aggArgTypes[i]);
592  }
593 
594  aclresult = object_aclcheck(TypeRelationId, aggTransType, GetUserId(), ACL_USAGE);
595  if (aclresult != ACLCHECK_OK)
596  aclcheck_error_type(aclresult, aggTransType);
597 
598  if (OidIsValid(aggmTransType))
599  {
600  aclresult = object_aclcheck(TypeRelationId, aggmTransType, GetUserId(), ACL_USAGE);
601  if (aclresult != ACLCHECK_OK)
602  aclcheck_error_type(aclresult, aggmTransType);
603  }
604 
605  aclresult = object_aclcheck(TypeRelationId, 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 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3810
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2941
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define Assert(condition)
Definition: c.h:837
#define OidIsValid(objectId)
Definition: c.h:754
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2742
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:72
#define RowExclusiveLock
Definition: lockdefs.h:38
bool func_strict(Oid funcid)
Definition: lsyscache.c:1761
Oid GetUserId(void)
Definition: miscinit.c:524
char * NameListToString(const List *names)
Definition: namespace.c:3594
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * check_valid_internal_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
char * check_valid_polymorphic_signature(Oid ret_type, const Oid *declared_arg_types, int nargs)
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:99
#define ACL_USAGE
Definition: parsenodes.h:84
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:826
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
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
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
ItemPointerData t_self
Definition: htup.h:65
TupleDesc rd_att
Definition: rel.h:112
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:712
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, add_exact_object_address(), 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(), object_aclcheck(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), ProcedureCreate(), RelationData::rd_att, record_object_address_dependencies(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), table_open(), oidvector::values, and values.

Referenced by DefineAggregate().

◆ CATALOG()

CATALOG ( pg_aggregate  ,
2600  ,
AggregateRelationId   
)

Definition at line 32 of file pg_aggregate.h.

33 {
34  /* pg_proc OID of the aggregate itself */
35  regproc aggfnoid BKI_LOOKUP(pg_proc);
36 
37  /* aggregate kind, see AGGKIND_ categories below */
38  char aggkind BKI_DEFAULT(n);
39 
40  /* number of arguments that are "direct" arguments */
41  int16 aggnumdirectargs BKI_DEFAULT(0);
42 
43  /* transition function */
44  regproc aggtransfn BKI_LOOKUP(pg_proc);
45 
46  /* final function (0 if none) */
47  regproc aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
48 
49  /* combine function (0 if none) */
50  regproc aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
51 
52  /* function to convert transtype to bytea (0 if none) */
53  regproc aggserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
54 
55  /* function to convert bytea to transtype (0 if none) */
56  regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
57 
58  /* forward function for moving-aggregate mode (0 if none) */
59  regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
60 
61  /* inverse function for moving-aggregate mode (0 if none) */
62  regproc aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
63 
64  /* final function for moving-aggregate mode (0 if none) */
65  regproc aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
66 
67  /* true to pass extra dummy arguments to aggfinalfn */
68  bool aggfinalextra BKI_DEFAULT(f);
69 
70  /* true to pass extra dummy arguments to aggmfinalfn */
71  bool aggmfinalextra BKI_DEFAULT(f);
72 
73  /* tells whether aggfinalfn modifies transition state */
74  char aggfinalmodify BKI_DEFAULT(r);
75 
76  /* tells whether aggmfinalfn modifies transition state */
77  char aggmfinalmodify BKI_DEFAULT(r);
78 
79  /* associated sort operator (0 if none) */
80  Oid aggsortop BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator);
81 
82  /* type of aggregate's transition (state) data */
83  Oid aggtranstype BKI_LOOKUP(pg_type);
84 
85  /* estimated size of state data (0 for default estimate) */
86  int32 aggtransspace BKI_DEFAULT(0);
87 
88  /* type of moving-aggregate state data (0 if none) */
89  Oid aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
90 
91  /* estimated size of moving-agg state (0 for default est) */
92  int32 aggmtransspace BKI_DEFAULT(0);
93 
94 #ifdef CATALOG_VARLEN /* variable-length fields start here */
95 
96  /* initial value for transition state (can be NULL) */
97  text agginitval BKI_DEFAULT(_null_);
98 
99  /* initial value for moving-agg state (can be NULL) */
100  text aggminitval BKI_DEFAULT(_null_);
101 #endif
signed short int16
Definition: c.h:481
signed int int32
Definition: c.h:482
Oid regproc
Definition: c.h:628
#define BKI_LOOKUP(catalog)
Definition: genbki.h:46
#define BKI_DEFAULT(value)
Definition: genbki.h:35
#define BKI_LOOKUP_OPT(catalog)
Definition: genbki.h:47
FormData_pg_aggregate
Definition: pg_aggregate.h:102
Definition: c.h:666

References BKI_DEFAULT, BKI_LOOKUP, and BKI_LOOKUP_OPT.

◆ DECLARE_TOAST()

DECLARE_TOAST ( pg_aggregate  ,
4159  ,
4160   
)

◆ DECLARE_UNIQUE_INDEX_PKEY()

DECLARE_UNIQUE_INDEX_PKEY ( pg_aggregate_fnoid_index  ,
2650  ,
AggregateFnoidIndexId  ,
pg_aggregate  ,
btree(aggfnoid oid_ops)   
)

◆ MAKE_SYSCACHE()

MAKE_SYSCACHE ( AGGFNOID  ,
pg_aggregate_fnoid_index  ,
16   
)

Variable Documentation

◆ FormData_pg_aggregate

FormData_pg_aggregate

Definition at line 102 of file pg_aggregate.h.