PostgreSQL Source Code git master
Loading...
Searching...
No Matches
aggregatecmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * aggregatecmds.c
4 *
5 * Routines for aggregate-manipulation commands
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/commands/aggregatecmds.c
13 *
14 * DESCRIPTION
15 * The "DefineAggregate" routine takes the parse tree and picks out the
16 * appropriate arguments/flags, passing the results to the
17 * "AggregateCreate" routine (in src/backend/catalog), which does the
18 * actual catalog-munging. DefineAggregate also verifies the permission of
19 * the user to execute the command.
20 *
21 *-------------------------------------------------------------------------
22 */
23#include "postgres.h"
24
25#include "catalog/namespace.h"
28#include "catalog/pg_proc.h"
29#include "catalog/pg_type.h"
30#include "commands/defrem.h"
31#include "miscadmin.h"
32#include "parser/parse_type.h"
33#include "utils/acl.h"
34#include "utils/builtins.h"
35#include "utils/lsyscache.h"
36
37
38static char extractModify(DefElem *defel);
39
40
41/*
42 * DefineAggregate
43 *
44 * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
45 * is specified by a BASETYPE element in the parameters. Otherwise,
46 * "args" is a pair, whose first element is a list of FunctionParameter structs
47 * defining the agg's arguments (both direct and aggregated), and whose second
48 * element is an Integer node with the number of direct args, or -1 if this
49 * isn't an ordered-set aggregate.
50 * "parameters" is a list of DefElem representing the agg's definition clauses.
51 */
54 List *name,
55 List *args,
56 bool oldstyle,
57 List *parameters,
58 bool replace)
59{
60 char *aggName;
72 bool finalfuncExtraArgs = false;
73 bool mfinalfuncExtraArgs = false;
74 char finalfuncModify = 0;
75 char mfinalfuncModify = 0;
77 TypeName *baseType = NULL;
80 int32 transSpace = 0;
82 char *initval = NULL;
83 char *minitval = NULL;
84 char *parallel = NULL;
85 int numArgs;
86 int numDirectArgs = 0;
87 oidvector *parameterTypes;
95 char transTypeType;
96 char mtransTypeType = 0;
98 ListCell *pl;
99
100 /* Convert list of names to a name and namespace */
102
103 /* Check we have creation rights in target namespace */
105 if (aclresult != ACLCHECK_OK)
108
109 /* Deconstruct the output of the aggr_args grammar production */
110 if (!oldstyle)
111 {
112 Assert(list_length(args) == 2);
114 if (numDirectArgs >= 0)
116 else
117 numDirectArgs = 0;
118 args = linitial_node(List, args);
119 }
120
121 /* Examine aggregate's definition clauses */
122 foreach(pl, parameters)
123 {
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)
132 else if (strcmp(defel->defname, "sfunc1") == 0)
134 else if (strcmp(defel->defname, "finalfunc") == 0)
136 else if (strcmp(defel->defname, "combinefunc") == 0)
138 else if (strcmp(defel->defname, "serialfunc") == 0)
140 else if (strcmp(defel->defname, "deserialfunc") == 0)
142 else if (strcmp(defel->defname, "msfunc") == 0)
144 else if (strcmp(defel->defname, "minvfunc") == 0)
146 else if (strcmp(defel->defname, "mfinalfunc") == 0)
148 else if (strcmp(defel->defname, "finalfunc_extra") == 0)
150 else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
152 else if (strcmp(defel->defname, "finalfunc_modify") == 0)
154 else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
156 else if (strcmp(defel->defname, "sortop") == 0)
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)
167 errmsg("only ordered-set aggregates can be hypothetical")));
169 }
170 }
171 else if (strcmp(defel->defname, "stype") == 0)
173 else if (strcmp(defel->defname, "stype1") == 0)
175 else if (strcmp(defel->defname, "sspace") == 0)
177 else if (strcmp(defel->defname, "mstype") == 0)
179 else if (strcmp(defel->defname, "msspace") == 0)
181 else if (strcmp(defel->defname, "initcond") == 0)
183 else if (strcmp(defel->defname, "initcond1") == 0)
185 else if (strcmp(defel->defname, "minitcond") == 0)
187 else if (strcmp(defel->defname, "parallel") == 0)
189 else
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)
202 errmsg("aggregate stype must be specified")));
203 if (transfuncName == NIL)
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)
218 errmsg("aggregate msfunc must be specified when mstype is specified")));
219 if (minvtransfuncName == NIL)
222 errmsg("aggregate minvfunc must be specified when mstype is specified")));
223 }
224 else
225 {
226 if (mtransfuncName != NIL)
229 errmsg("aggregate msfunc must not be specified without mstype")));
230 if (minvtransfuncName != NIL)
233 errmsg("aggregate minvfunc must not be specified without mstype")));
234 if (mfinalfuncName != NIL)
237 errmsg("aggregate mfinalfunc must not be specified without mstype")));
238 if (mtransSpace != 0)
241 errmsg("aggregate msspace must not be specified without mstype")));
242 if (minitval != NULL)
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)
254 if (mfinalfuncModify == 0)
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)
274 errmsg("aggregate input type must be specified")));
275
276 if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
277 {
278 numArgs = 0;
280 }
281 else
282 {
283 numArgs = 1;
284 aggArgTypes[0] = typenameTypeId(NULL, baseType);
285 }
286 parameterTypes = buildoidvector(aggArgTypes, numArgs);
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 */
300
301 if (baseType != NULL)
304 errmsg("basetype is redundant with aggregate input type specification")));
305
306 numArgs = list_length(args);
308 args,
311 &parameterTypes,
312 NULL,
316 NULL,
320 /* Parameter defaults are not currently allowed by the grammar */
322 /* There shouldn't have been any OUT parameters, either */
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 */
341 {
343 /* okay */ ;
344 else
347 errmsg("aggregate transition data type cannot be %s",
349 }
350
352 {
353 /*
354 * Serialization is only needed/allowed for transtype INTERNAL.
355 */
359 errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
361 }
363 {
364 /*
365 * Cannot specify one function without the other.
366 */
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 {
382 {
384 /* okay */ ;
385 else
388 errmsg("aggregate transition data type cannot be %s",
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 */
403 {
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 */
415 {
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)
427 else if (strcmp(parallel, "restricted") == 0)
429 else if (strcmp(parallel, "unsafe") == 0)
431 else
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,
446 parameterTypes,
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 */
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}
473
474/*
475 * Convert the string form of [m]finalfunc_modify to the catalog representation
476 */
477static char
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)
490 errmsg("parameter \"%s\" must be READ_ONLY, SHAREABLE, or READ_WRITE",
491 defel->defname)));
492 return 0; /* keep compiler quiet */
493}
AclResult
Definition acl.h:182
@ ACLCHECK_OK
Definition acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3836
static char extractModify(DefElem *defel)
ObjectAddress DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters, bool replace)
#define Assert(condition)
Definition c.h:873
int32_t int32
Definition c.h:542
TypeName * defGetTypeName(DefElem *def)
Definition define.c:270
int32 defGetInt32(DefElem *def)
Definition define.c:148
char * defGetString(DefElem *def)
Definition define.c:34
bool defGetBoolean(DefElem *def)
Definition define.c:93
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition fmgr.c:1754
char * format_type_be(Oid type_oid)
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)
long val
Definition informix.c:689
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3024
char get_typtype(Oid typid)
Definition lsyscache.c:2779
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
Oid GetUserId(void)
Definition miscinit.c:469
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3557
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
@ OBJECT_SCHEMA
#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)
#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)
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
#define InvalidOid
unsigned int Oid
static int fb(int x)
Definition pg_list.h:54
Definition c.h:745
bool superuser(void)
Definition superuser.c:46
#define intVal(v)
Definition value.h:79
const char * name