PostgreSQL Source Code git master
aggregatecmds.c File Reference
#include "postgres.h"
#include "catalog/namespace.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
Include dependency graph for aggregatecmds.c:

Go to the source code of this file.

Functions

static char extractModify (DefElem *defel)
 
ObjectAddress DefineAggregate (ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters, bool replace)
 

Function Documentation

◆ DefineAggregate()

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

Definition at line 53 of file aggregatecmds.c.

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

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, AggregateCreate(), generate_unaccent_rules::args, Assert(), buildoidvector(), defGetBoolean(), defGetInt32(), defGetQualifiedName(), defGetString(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, extractModify(), format_type_be(), get_namespace_name(), get_typtype(), getTypeInputInfo(), GetUserId(), interpret_function_parameter_list(), intVal, InvalidOid, lfirst_node, linitial_node, list_length(), lsecond, name, NIL, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_SCHEMA, OidInputFunctionCall(), pg_strcasecmp(), PointerGetDatum(), QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ extractModify()

static char extractModify ( DefElem defel)
static

Definition at line 478 of file aggregatecmds.c.

479{
480 char *val = defGetString(defel);
481
482 if (strcmp(val, "read_only") == 0)
483 return AGGMODIFY_READ_ONLY;
484 if (strcmp(val, "shareable") == 0)
485 return AGGMODIFY_SHAREABLE;
486 if (strcmp(val, "read_write") == 0)
487 return AGGMODIFY_READ_WRITE;
489 (errcode(ERRCODE_SYNTAX_ERROR),
490 errmsg("parameter \"%s\" must be READ_ONLY, SHAREABLE, or READ_WRITE",
491 defel->defname)));
492 return 0; /* keep compiler quiet */
493}
long val
Definition: informix.c:689

References defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, and val.

Referenced by DefineAggregate().