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)
 
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.

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

◆ 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:354
unsigned int Oid
Definition: postgres_ext.h:31
#define BKI_DEFAULT(value)
Definition: genbki.h:35
signed int int32
Definition: c.h:355
FormData_pg_aggregate
Definition: pg_aggregate.h:102
#define BKI_LOOKUP(catalog)
Definition: genbki.h:42
Oid regproc
Definition: c.h:510
Definition: c.h:555

Variable Documentation

◆ FormData_pg_aggregate

FormData_pg_aggregate

Definition at line 102 of file pg_aggregate.h.