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

Variable Documentation

◆ FormData_pg_aggregate

FormData_pg_aggregate

Definition at line 102 of file pg_aggregate.h.