PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
aggregatecmds.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for aggregatecmds.c:

Go to the source code of this file.

Functions

ObjectAddress DefineAggregate (ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters)
 

Function Documentation

ObjectAddress DefineAggregate ( ParseState pstate,
List name,
List args,
bool  oldstyle,
List parameters 
)

Definition at line 54 of file aggregatecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, AGGKIND_HYPOTHETICAL, AGGKIND_NORMAL, AGGKIND_ORDERED_SET, AggregateCreate(), Assert, buildoidvector(), defGetBoolean(), defGetInt32(), defGetQualifiedName(), defGetString(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_typtype(), getTypeInputInfo(), GetUserId(), INTERNALOID, interpret_function_parameter_list(), intVal, InvalidOid, IsPolymorphicType, lfirst_node, linitial_node, list_length(), lsecond, NIL, NULL, OidInputFunctionCall(), pg_namespace_aclcheck(), pg_strcasecmp(), PointerGetDatum, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE, PROPARALLEL_UNSAFE, QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), TYPTYPE_PSEUDO, and WARNING.

Referenced by ProcessUtilitySlow().

55 {
56  char *aggName;
57  Oid aggNamespace;
58  AclResult aclresult;
59  char aggKind = AGGKIND_NORMAL;
60  List *transfuncName = NIL;
61  List *finalfuncName = NIL;
62  List *combinefuncName = NIL;
63  List *serialfuncName = NIL;
64  List *deserialfuncName = NIL;
65  List *mtransfuncName = NIL;
66  List *minvtransfuncName = NIL;
67  List *mfinalfuncName = NIL;
68  bool finalfuncExtraArgs = false;
69  bool mfinalfuncExtraArgs = false;
70  List *sortoperatorName = NIL;
71  TypeName *baseType = NULL;
72  TypeName *transType = NULL;
73  TypeName *mtransType = NULL;
74  int32 transSpace = 0;
75  int32 mtransSpace = 0;
76  char *initval = NULL;
77  char *minitval = NULL;
78  char *parallel = NULL;
79  int numArgs;
80  int numDirectArgs = 0;
81  oidvector *parameterTypes;
82  ArrayType *allParameterTypes;
83  ArrayType *parameterModes;
84  ArrayType *parameterNames;
85  List *parameterDefaults;
86  Oid variadicArgType;
87  Oid transTypeId;
88  Oid mtransTypeId = InvalidOid;
89  char transTypeType;
90  char mtransTypeType = 0;
91  char proparallel = PROPARALLEL_UNSAFE;
92  ListCell *pl;
93 
94  /* Convert list of names to a name and namespace */
95  aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
96 
97  /* Check we have creation rights in target namespace */
98  aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
99  if (aclresult != ACLCHECK_OK)
101  get_namespace_name(aggNamespace));
102 
103  /* Deconstruct the output of the aggr_args grammar production */
104  if (!oldstyle)
105  {
106  Assert(list_length(args) == 2);
107  numDirectArgs = intVal(lsecond(args));
108  if (numDirectArgs >= 0)
109  aggKind = AGGKIND_ORDERED_SET;
110  else
111  numDirectArgs = 0;
112  args = linitial_node(List, args);
113  }
114 
115  /* Examine aggregate's definition clauses */
116  foreach(pl, parameters)
117  {
118  DefElem *defel = lfirst_node(DefElem, pl);
119 
120  /*
121  * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
122  * for sfunc, stype, initcond.
123  */
124  if (pg_strcasecmp(defel->defname, "sfunc") == 0)
125  transfuncName = defGetQualifiedName(defel);
126  else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
127  transfuncName = defGetQualifiedName(defel);
128  else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
129  finalfuncName = defGetQualifiedName(defel);
130  else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
131  combinefuncName = defGetQualifiedName(defel);
132  else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
133  serialfuncName = defGetQualifiedName(defel);
134  else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
135  deserialfuncName = defGetQualifiedName(defel);
136  else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
137  mtransfuncName = defGetQualifiedName(defel);
138  else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
139  minvtransfuncName = defGetQualifiedName(defel);
140  else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
141  mfinalfuncName = defGetQualifiedName(defel);
142  else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
143  finalfuncExtraArgs = defGetBoolean(defel);
144  else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
145  mfinalfuncExtraArgs = defGetBoolean(defel);
146  else if (pg_strcasecmp(defel->defname, "sortop") == 0)
147  sortoperatorName = defGetQualifiedName(defel);
148  else if (pg_strcasecmp(defel->defname, "basetype") == 0)
149  baseType = defGetTypeName(defel);
150  else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
151  {
152  if (defGetBoolean(defel))
153  {
154  if (aggKind == AGGKIND_NORMAL)
155  ereport(ERROR,
156  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
157  errmsg("only ordered-set aggregates can be hypothetical")));
158  aggKind = AGGKIND_HYPOTHETICAL;
159  }
160  }
161  else if (pg_strcasecmp(defel->defname, "stype") == 0)
162  transType = defGetTypeName(defel);
163  else if (pg_strcasecmp(defel->defname, "stype1") == 0)
164  transType = defGetTypeName(defel);
165  else if (pg_strcasecmp(defel->defname, "sspace") == 0)
166  transSpace = defGetInt32(defel);
167  else if (pg_strcasecmp(defel->defname, "mstype") == 0)
168  mtransType = defGetTypeName(defel);
169  else if (pg_strcasecmp(defel->defname, "msspace") == 0)
170  mtransSpace = defGetInt32(defel);
171  else if (pg_strcasecmp(defel->defname, "initcond") == 0)
172  initval = defGetString(defel);
173  else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
174  initval = defGetString(defel);
175  else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
176  minitval = defGetString(defel);
177  else if (pg_strcasecmp(defel->defname, "parallel") == 0)
178  parallel = defGetString(defel);
179  else
181  (errcode(ERRCODE_SYNTAX_ERROR),
182  errmsg("aggregate attribute \"%s\" not recognized",
183  defel->defname)));
184  }
185 
186  /*
187  * make sure we have our required definitions
188  */
189  if (transType == NULL)
190  ereport(ERROR,
191  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
192  errmsg("aggregate stype must be specified")));
193  if (transfuncName == NIL)
194  ereport(ERROR,
195  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
196  errmsg("aggregate sfunc must be specified")));
197 
198  /*
199  * if mtransType is given, mtransfuncName and minvtransfuncName must be as
200  * well; if not, then none of the moving-aggregate options should have
201  * been given.
202  */
203  if (mtransType != NULL)
204  {
205  if (mtransfuncName == NIL)
206  ereport(ERROR,
207  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
208  errmsg("aggregate msfunc must be specified when mstype is specified")));
209  if (minvtransfuncName == NIL)
210  ereport(ERROR,
211  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
212  errmsg("aggregate minvfunc must be specified when mstype is specified")));
213  }
214  else
215  {
216  if (mtransfuncName != NIL)
217  ereport(ERROR,
218  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
219  errmsg("aggregate msfunc must not be specified without mstype")));
220  if (minvtransfuncName != NIL)
221  ereport(ERROR,
222  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
223  errmsg("aggregate minvfunc must not be specified without mstype")));
224  if (mfinalfuncName != NIL)
225  ereport(ERROR,
226  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
227  errmsg("aggregate mfinalfunc must not be specified without mstype")));
228  if (mtransSpace != 0)
229  ereport(ERROR,
230  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
231  errmsg("aggregate msspace must not be specified without mstype")));
232  if (minitval != NULL)
233  ereport(ERROR,
234  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
235  errmsg("aggregate minitcond must not be specified without mstype")));
236  }
237 
238  /*
239  * look up the aggregate's input datatype(s).
240  */
241  if (oldstyle)
242  {
243  /*
244  * Old style: use basetype parameter. This supports aggregates of
245  * zero or one input, with input type ANY meaning zero inputs.
246  *
247  * Historically we allowed the command to look like basetype = 'ANY'
248  * so we must do a case-insensitive comparison for the name ANY. Ugh.
249  */
250  Oid aggArgTypes[1];
251 
252  if (baseType == NULL)
253  ereport(ERROR,
254  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
255  errmsg("aggregate input type must be specified")));
256 
257  if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
258  {
259  numArgs = 0;
260  aggArgTypes[0] = InvalidOid;
261  }
262  else
263  {
264  numArgs = 1;
265  aggArgTypes[0] = typenameTypeId(NULL, baseType);
266  }
267  parameterTypes = buildoidvector(aggArgTypes, numArgs);
268  allParameterTypes = NULL;
269  parameterModes = NULL;
270  parameterNames = NULL;
271  parameterDefaults = NIL;
272  variadicArgType = InvalidOid;
273  }
274  else
275  {
276  /*
277  * New style: args is a list of FunctionParameters (possibly zero of
278  * 'em). We share functioncmds.c's code for processing them.
279  */
280  Oid requiredResultType;
281 
282  if (baseType != NULL)
283  ereport(ERROR,
284  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
285  errmsg("basetype is redundant with aggregate input type specification")));
286 
287  numArgs = list_length(args);
289  args,
290  InvalidOid,
291  true, /* is an aggregate */
292  &parameterTypes,
293  &allParameterTypes,
294  &parameterModes,
295  &parameterNames,
296  &parameterDefaults,
297  &variadicArgType,
298  &requiredResultType);
299  /* Parameter defaults are not currently allowed by the grammar */
300  Assert(parameterDefaults == NIL);
301  /* There shouldn't have been any OUT parameters, either */
302  Assert(requiredResultType == InvalidOid);
303  }
304 
305  /*
306  * look up the aggregate's transtype.
307  *
308  * transtype can't be a pseudo-type, since we need to be able to store
309  * values of the transtype. However, we can allow polymorphic transtype
310  * in some cases (AggregateCreate will check). Also, we allow "internal"
311  * for functions that want to pass pointers to private data structures;
312  * but allow that only to superusers, since you could crash the system (or
313  * worse) by connecting up incompatible internal-using functions in an
314  * aggregate.
315  */
316  transTypeId = typenameTypeId(NULL, transType);
317  transTypeType = get_typtype(transTypeId);
318  if (transTypeType == TYPTYPE_PSEUDO &&
319  !IsPolymorphicType(transTypeId))
320  {
321  if (transTypeId == INTERNALOID && superuser())
322  /* okay */ ;
323  else
324  ereport(ERROR,
325  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
326  errmsg("aggregate transition data type cannot be %s",
327  format_type_be(transTypeId))));
328  }
329 
330  if (serialfuncName && deserialfuncName)
331  {
332  /*
333  * Serialization is only needed/allowed for transtype INTERNAL.
334  */
335  if (transTypeId != INTERNALOID)
336  ereport(ERROR,
337  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
338  errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
340  }
341  else if (serialfuncName || deserialfuncName)
342  {
343  /*
344  * Cannot specify one function without the other.
345  */
346  ereport(ERROR,
347  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
348  errmsg("must specify both or neither of serialization and deserialization functions")));
349  }
350 
351  /*
352  * If a moving-aggregate transtype is specified, look that up. Same
353  * restrictions as for transtype.
354  */
355  if (mtransType)
356  {
357  mtransTypeId = typenameTypeId(NULL, mtransType);
358  mtransTypeType = get_typtype(mtransTypeId);
359  if (mtransTypeType == TYPTYPE_PSEUDO &&
360  !IsPolymorphicType(mtransTypeId))
361  {
362  if (mtransTypeId == INTERNALOID && superuser())
363  /* okay */ ;
364  else
365  ereport(ERROR,
366  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367  errmsg("aggregate transition data type cannot be %s",
368  format_type_be(mtransTypeId))));
369  }
370  }
371 
372  /*
373  * If we have an initval, and it's not for a pseudotype (particularly a
374  * polymorphic type), make sure it's acceptable to the type's input
375  * function. We will store the initval as text, because the input
376  * function isn't necessarily immutable (consider "now" for timestamp),
377  * and we want to use the runtime not creation-time interpretation of the
378  * value. However, if it's an incorrect value it seems much more
379  * user-friendly to complain at CREATE AGGREGATE time.
380  */
381  if (initval && transTypeType != TYPTYPE_PSEUDO)
382  {
383  Oid typinput,
384  typioparam;
385 
386  getTypeInputInfo(transTypeId, &typinput, &typioparam);
387  (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
388  }
389 
390  /*
391  * Likewise for moving-aggregate initval.
392  */
393  if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
394  {
395  Oid typinput,
396  typioparam;
397 
398  getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
399  (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
400  }
401 
402  if (parallel)
403  {
404  if (pg_strcasecmp(parallel, "safe") == 0)
405  proparallel = PROPARALLEL_SAFE;
406  else if (pg_strcasecmp(parallel, "restricted") == 0)
407  proparallel = PROPARALLEL_RESTRICTED;
408  else if (pg_strcasecmp(parallel, "unsafe") == 0)
409  proparallel = PROPARALLEL_UNSAFE;
410  else
411  ereport(ERROR,
412  (errcode(ERRCODE_SYNTAX_ERROR),
413  errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
414  }
415 
416  /*
417  * Most of the argument-checking is done inside of AggregateCreate
418  */
419  return AggregateCreate(aggName, /* aggregate name */
420  aggNamespace, /* namespace */
421  aggKind,
422  numArgs,
423  numDirectArgs,
424  parameterTypes,
425  PointerGetDatum(allParameterTypes),
426  PointerGetDatum(parameterModes),
427  PointerGetDatum(parameterNames),
428  parameterDefaults,
429  variadicArgType,
430  transfuncName, /* step function name */
431  finalfuncName, /* final function name */
432  combinefuncName, /* combine function name */
433  serialfuncName, /* serial function name */
434  deserialfuncName, /* deserial function name */
435  mtransfuncName, /* fwd trans function name */
436  minvtransfuncName, /* inv trans function name */
437  mfinalfuncName, /* final function name */
438  finalfuncExtraArgs,
439  mfinalfuncExtraArgs,
440  sortoperatorName, /* sort operator name */
441  transTypeId, /* transition data type */
442  transSpace, /* transition space */
443  mtransTypeId, /* transition data type */
444  mtransSpace, /* transition space */
445  initval, /* initial condition */
446  minitval, /* initial condition */
447  proparallel); /* parallel safe? */
448 }
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, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
Definition: pg_aggregate.c:47
#define NIL
Definition: pg_list.h:69
Definition: c.h:478
Oid GetUserId(void)
Definition: miscinit.c:283
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
#define PointerGetDatum(X)
Definition: postgres.h:562
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
int32 defGetInt32(DefElem *def)
Definition: define.c:166
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
char get_typtype(Oid typid)
Definition: lsyscache.c:2379
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define PROPARALLEL_RESTRICTED
Definition: pg_proc.h:5489
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
#define linitial_node(type, l)
Definition: pg_list.h:114
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define lsecond(l)
Definition: pg_list.h:116
signed int int32
Definition: c.h:256
void interpret_function_parameter_list(ParseState *pstate, List *parameters, Oid languageOid, bool is_aggregate, oidvector **parameterTypes, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
Definition: functioncmds.c:179
bool defGetBoolean(DefElem *def)
Definition: define.c:111
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
#define IsPolymorphicType(typid)
Definition: pg_type.h:745
char * defGetString(DefElem *def)
Definition: define.c:49
#define lfirst_node(type, lc)
Definition: pg_list.h:109
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3038
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define AGGKIND_NORMAL
Definition: pg_aggregate.h:124
#define PROPARALLEL_SAFE
Definition: pg_proc.h:5488
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2599
#define ereport(elevel, rest)
Definition: elog.h:122
#define PROPARALLEL_UNSAFE
Definition: pg_proc.h:5490
#define WARNING
Definition: elog.h:40
AclResult
Definition: acl.h:170
#define InvalidOid
Definition: postgres_ext.h:36
#define INTERNALOID
Definition: pg_type.h:698
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:167
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
static int list_length(const List *l)
Definition: pg_list.h:89
#define TYPTYPE_PSEUDO
Definition: pg_type.h:724
#define intVal(v)
Definition: value.h:52
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * defname
Definition: parsenodes.h:719
#define AGGKIND_HYPOTHETICAL
Definition: pg_aggregate.h:126
Definition: pg_list.h:45
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1738
#define AGGKIND_ORDERED_SET
Definition: pg_aggregate.h:125
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274