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

Variables

 FormData_pg_aggregate
 

Typedef Documentation

◆ Form_pg_aggregate

Function Documentation

◆ AggregateCreate()

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

Definition at line 46 of file pg_aggregate.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, Assert, BoolGetDatum, CatalogTupleInsert(), CharGetDatum, ObjectAddress::classId, CStringGetTextDatum, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), errmsg_plural(), ERROR, format_type_be(), FUNC_MAX_ARGS, func_strict(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_open(), HeapTupleIsValid, i, Int16GetDatum, Int32GetDatum, InvalidOid, IsBinaryCoercible(), lookup_agg_function(), LookupOperName(), NameListToString(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, pg_type_aclcheck(), PointerGetDatum, ProcedureCreate(), PROCOID, RelationData::rd_att, recordDependencyOn(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), values, and oidvector::values.

Referenced by DefineAggregate().

77 {
78  Relation aggdesc;
79  HeapTuple tup;
80  bool nulls[Natts_pg_aggregate];
81  Datum values[Natts_pg_aggregate];
82  Form_pg_proc proc;
83  Oid transfn;
84  Oid finalfn = InvalidOid; /* can be omitted */
85  Oid combinefn = InvalidOid; /* can be omitted */
86  Oid serialfn = InvalidOid; /* can be omitted */
87  Oid deserialfn = InvalidOid; /* can be omitted */
88  Oid mtransfn = InvalidOid; /* can be omitted */
89  Oid minvtransfn = InvalidOid; /* can be omitted */
90  Oid mfinalfn = InvalidOid; /* can be omitted */
91  Oid sortop = InvalidOid; /* can be omitted */
92  Oid *aggArgTypes = parameterTypes->values;
93  bool hasPolyArg;
94  bool hasInternalArg;
95  bool mtransIsStrict = false;
96  Oid rettype;
97  Oid finaltype;
98  Oid fnArgs[FUNC_MAX_ARGS];
99  int nargs_transfn;
100  int nargs_finalfn;
101  Oid procOid;
102  TupleDesc tupDesc;
103  int i;
104  ObjectAddress myself,
105  referenced;
106  AclResult aclresult;
107 
108  /* sanity checks (caller should have caught these) */
109  if (!aggName)
110  elog(ERROR, "no aggregate name supplied");
111 
112  if (!aggtransfnName)
113  elog(ERROR, "aggregate must have a transition function");
114 
115  if (numDirectArgs < 0 || numDirectArgs > numArgs)
116  elog(ERROR, "incorrect number of direct args for aggregate");
117 
118  /*
119  * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
120  * and/or finalfn will be unrepresentable in pg_proc. We must check now
121  * to protect fixed-size arrays here and possibly in called functions.
122  */
123  if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
124  ereport(ERROR,
125  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
126  errmsg_plural("aggregates cannot have more than %d argument",
127  "aggregates cannot have more than %d arguments",
128  FUNC_MAX_ARGS - 1,
129  FUNC_MAX_ARGS - 1)));
130 
131  /* check for polymorphic and INTERNAL arguments */
132  hasPolyArg = false;
133  hasInternalArg = false;
134  for (i = 0; i < numArgs; i++)
135  {
136  if (IsPolymorphicType(aggArgTypes[i]))
137  hasPolyArg = true;
138  else if (aggArgTypes[i] == INTERNALOID)
139  hasInternalArg = true;
140  }
141 
142  /*
143  * If transtype is polymorphic, must have polymorphic argument also; else
144  * we will have no way to deduce the actual transtype.
145  */
146  if (IsPolymorphicType(aggTransType) && !hasPolyArg)
147  ereport(ERROR,
148  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
149  errmsg("cannot determine transition data type"),
150  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
151 
152  /*
153  * Likewise for moving-aggregate transtype, if any
154  */
155  if (OidIsValid(aggmTransType) &&
156  IsPolymorphicType(aggmTransType) && !hasPolyArg)
157  ereport(ERROR,
158  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
159  errmsg("cannot determine transition data type"),
160  errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
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  if (IsPolymorphicType(finaltype) && !hasPolyArg)
493  ereport(ERROR,
494  (errcode(ERRCODE_DATATYPE_MISMATCH),
495  errmsg("cannot determine result data type"),
496  errdetail("An aggregate returning a polymorphic type "
497  "must have at least one polymorphic argument.")));
498 
499  /*
500  * Also, the return type can't be INTERNAL unless there's at least one
501  * INTERNAL argument. This is the same type-safety restriction we enforce
502  * for regular functions, but at the level of aggregates. We must test
503  * this explicitly because we allow INTERNAL as the transtype.
504  */
505  if (finaltype == INTERNALOID && !hasInternalArg)
506  ereport(ERROR,
507  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
508  errmsg("unsafe use of pseudo-type \"internal\""),
509  errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
510 
511  /*
512  * If a moving-aggregate implementation is supplied, look up its finalfn
513  * if any, and check that the implied aggregate result type matches the
514  * plain implementation.
515  */
516  if (OidIsValid(aggmTransType))
517  {
518  /* handle finalfn, if supplied */
519  if (aggmfinalfnName)
520  {
521  /*
522  * The arguments are figured the same way as for the regular
523  * finalfn, but using aggmTransType and mfinalfnExtraArgs.
524  */
525  Oid ffnVariadicArgType = variadicArgType;
526 
527  fnArgs[0] = aggmTransType;
528  memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
529  if (mfinalfnExtraArgs)
530  nargs_finalfn = numArgs + 1;
531  else
532  {
533  nargs_finalfn = numDirectArgs + 1;
534  if (numDirectArgs < numArgs)
535  {
536  /* variadic argument doesn't affect finalfn */
537  ffnVariadicArgType = InvalidOid;
538  }
539  }
540 
541  mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
542  fnArgs, ffnVariadicArgType,
543  &rettype);
544 
545  /* As above, check strictness if mfinalfnExtraArgs is given */
546  if (mfinalfnExtraArgs && func_strict(mfinalfn))
547  ereport(ERROR,
548  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
549  errmsg("final function with extra arguments must not be declared STRICT")));
550  }
551  else
552  {
553  /*
554  * If no finalfn, aggregate result type is type of the state value
555  */
556  rettype = aggmTransType;
557  }
558  Assert(OidIsValid(rettype));
559  if (rettype != finaltype)
560  ereport(ERROR,
561  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
562  errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
563  format_type_be(aggmTransType),
564  format_type_be(aggTransType))));
565  }
566 
567  /* handle sortop, if supplied */
568  if (aggsortopName)
569  {
570  if (numArgs != 1)
571  ereport(ERROR,
572  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
573  errmsg("sort operator can only be specified for single-argument aggregates")));
574  sortop = LookupOperName(NULL, aggsortopName,
575  aggArgTypes[0], aggArgTypes[0],
576  false, -1);
577  }
578 
579  /*
580  * permission checks on used types
581  */
582  for (i = 0; i < numArgs; i++)
583  {
584  aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
585  if (aclresult != ACLCHECK_OK)
586  aclcheck_error_type(aclresult, aggArgTypes[i]);
587  }
588 
589  aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
590  if (aclresult != ACLCHECK_OK)
591  aclcheck_error_type(aclresult, aggTransType);
592 
593  if (OidIsValid(aggmTransType))
594  {
595  aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
596  if (aclresult != ACLCHECK_OK)
597  aclcheck_error_type(aclresult, aggmTransType);
598  }
599 
600  aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
601  if (aclresult != ACLCHECK_OK)
602  aclcheck_error_type(aclresult, finaltype);
603 
604 
605  /*
606  * Everything looks okay. Try to create the pg_proc entry for the
607  * aggregate. (This could fail if there's already a conflicting entry.)
608  */
609 
610  myself = ProcedureCreate(aggName,
611  aggNamespace,
612  false, /* no replacement */
613  false, /* doesn't return a set */
614  finaltype, /* returnType */
615  GetUserId(), /* proowner */
616  INTERNALlanguageId, /* languageObjectId */
617  InvalidOid, /* no validator */
618  "aggregate_dummy", /* placeholder proc */
619  NULL, /* probin */
620  PROKIND_AGGREGATE,
621  false, /* security invoker (currently not
622  * definable for agg) */
623  false, /* isLeakProof */
624  false, /* isStrict (not needed for agg) */
625  PROVOLATILE_IMMUTABLE, /* volatility (not needed
626  * for agg) */
627  proparallel,
628  parameterTypes, /* paramTypes */
629  allParameterTypes, /* allParamTypes */
630  parameterModes, /* parameterModes */
631  parameterNames, /* parameterNames */
632  parameterDefaults, /* parameterDefaults */
633  PointerGetDatum(NULL), /* trftypes */
634  PointerGetDatum(NULL), /* proconfig */
635  1, /* procost */
636  0); /* prorows */
637  procOid = myself.objectId;
638 
639  /*
640  * Okay to create the pg_aggregate entry.
641  */
642 
643  /* initialize nulls and values */
644  for (i = 0; i < Natts_pg_aggregate; i++)
645  {
646  nulls[i] = false;
647  values[i] = (Datum) NULL;
648  }
649  values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
650  values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
651  values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
652  values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
653  values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
654  values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
655  values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
656  values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
657  values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
658  values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
659  values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
660  values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
661  values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
662  values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
663  values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
664  values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
665  values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
666  values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
667  values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
668  values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
669  if (agginitval)
670  values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
671  else
672  nulls[Anum_pg_aggregate_agginitval - 1] = true;
673  if (aggminitval)
674  values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
675  else
676  nulls[Anum_pg_aggregate_aggminitval - 1] = true;
677 
678  aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
679  tupDesc = aggdesc->rd_att;
680 
681  tup = heap_form_tuple(tupDesc, values, nulls);
682  CatalogTupleInsert(aggdesc, tup);
683 
684  heap_close(aggdesc, RowExclusiveLock);
685 
686  /*
687  * Create dependencies for the aggregate (above and beyond those already
688  * made by ProcedureCreate). Note: we don't need an explicit dependency
689  * on aggTransType since we depend on it indirectly through transfn.
690  * Likewise for aggmTransType using the mtransfunc, if it exists.
691  */
692 
693  /* Depends on transition function */
694  referenced.classId = ProcedureRelationId;
695  referenced.objectId = transfn;
696  referenced.objectSubId = 0;
697  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
698 
699  /* Depends on final function, if any */
700  if (OidIsValid(finalfn))
701  {
702  referenced.classId = ProcedureRelationId;
703  referenced.objectId = finalfn;
704  referenced.objectSubId = 0;
705  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
706  }
707 
708  /* Depends on combine function, if any */
709  if (OidIsValid(combinefn))
710  {
711  referenced.classId = ProcedureRelationId;
712  referenced.objectId = combinefn;
713  referenced.objectSubId = 0;
714  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
715  }
716 
717  /* Depends on serialization function, if any */
718  if (OidIsValid(serialfn))
719  {
720  referenced.classId = ProcedureRelationId;
721  referenced.objectId = serialfn;
722  referenced.objectSubId = 0;
723  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
724  }
725 
726  /* Depends on deserialization function, if any */
727  if (OidIsValid(deserialfn))
728  {
729  referenced.classId = ProcedureRelationId;
730  referenced.objectId = deserialfn;
731  referenced.objectSubId = 0;
732  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
733  }
734 
735  /* Depends on forward transition function, if any */
736  if (OidIsValid(mtransfn))
737  {
738  referenced.classId = ProcedureRelationId;
739  referenced.objectId = mtransfn;
740  referenced.objectSubId = 0;
741  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
742  }
743 
744  /* Depends on inverse transition function, if any */
745  if (OidIsValid(minvtransfn))
746  {
747  referenced.classId = ProcedureRelationId;
748  referenced.objectId = minvtransfn;
749  referenced.objectSubId = 0;
750  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
751  }
752 
753  /* Depends on final function, if any */
754  if (OidIsValid(mfinalfn))
755  {
756  referenced.classId = ProcedureRelationId;
757  referenced.objectId = mfinalfn;
758  referenced.objectSubId = 0;
759  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
760  }
761 
762  /* Depends on sort operator, if any */
763  if (OidIsValid(sortop))
764  {
765  referenced.classId = OperatorRelationId;
766  referenced.objectId = sortop;
767  referenced.objectSubId = 0;
768  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
769  }
770 
771  return myself;
772 }
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, float4 procost, float4 prorows)
Definition: pg_proc.c:66
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
Oid GetUserId(void)
Definition: miscinit.c:379
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:850
#define PointerGetDatum(X)
Definition: postgres.h:541
#define Int16GetDatum(X)
Definition: postgres.h:436
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:102
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
#define FUNC_MAX_ARGS
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:563
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ACL_USAGE
Definition: parsenodes.h:82
#define ereport(elevel, rest)
Definition: elog.h:122
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid variadicArgType, Oid *rettype)
Definition: pg_aggregate.c:787
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3082
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:132
#define BoolGetDatum(X)
Definition: postgres.h:387
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
bool func_strict(Oid funcid)
Definition: lsyscache.c:1550
#define CharGetDatum(X)
Definition: postgres.h:401
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:464
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:95
#define elog
Definition: elog.h:219
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4739

◆ CATALOG()

CATALOG ( pg_aggregate  ,
2600  ,
AggregateRelationId   
)

Definition at line 32 of file pg_aggregate.h.

References BKI_DEFAULT, and BKI_LOOKUP.

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(pg_proc);
48 
49  /* combine function (0 if none) */
50  regproc aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
51 
52  /* function to convert transtype to bytea (0 if none) */
53  regproc aggserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
54 
55  /* function to convert bytea to transtype (0 if none) */
56  regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
57 
58  /* forward function for moving-aggregate mode (0 if none) */
59  regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
60 
61  /* inverse function for moving-aggregate mode (0 if none) */
62  regproc aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
63 
64  /* final function for moving-aggregate mode (0 if none) */
65  regproc aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP(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(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(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:312
unsigned int Oid
Definition: postgres_ext.h:31
#define BKI_DEFAULT(value)
Definition: genbki.h:36
signed int int32
Definition: c.h:313
FormData_pg_aggregate
Definition: pg_aggregate.h:102
#define BKI_LOOKUP(catalog)
Definition: genbki.h:38
Oid regproc
Definition: c.h:471
Definition: c.h:516

Variable Documentation

◆ FormData_pg_aggregate

FormData_pg_aggregate

Definition at line 102 of file pg_aggregate.h.