TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * aggregatecmds.c
4 : *
5 : * Routines for aggregate-manipulation commands
6 : *
7 : * Portions Copyright (c) 1996-2023, 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 "DefineFoo" routines take the parse tree and pick out the
16 : * appropriate arguments/flags, passing the results to the
17 : * corresponding "FooDefine" routines (in src/catalog) that do
18 : * the actual catalog-munging. These routines also verify permission
19 : * of the user to execute the command.
20 : *
21 : *-------------------------------------------------------------------------
22 : */
23 : #include "postgres.h"
24 :
25 : #include "access/htup_details.h"
26 : #include "catalog/dependency.h"
27 : #include "catalog/pg_aggregate.h"
28 : #include "catalog/pg_namespace.h"
29 : #include "catalog/pg_proc.h"
30 : #include "catalog/pg_type.h"
31 : #include "commands/alter.h"
32 : #include "commands/defrem.h"
33 : #include "miscadmin.h"
34 : #include "parser/parse_func.h"
35 : #include "parser/parse_type.h"
36 : #include "utils/acl.h"
37 : #include "utils/builtins.h"
38 : #include "utils/lsyscache.h"
39 : #include "utils/syscache.h"
40 :
41 :
42 : static char extractModify(DefElem *defel);
43 :
44 :
45 : /*
46 : * DefineAggregate
47 : *
48 : * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
49 : * is specified by a BASETYPE element in the parameters. Otherwise,
50 : * "args" is a pair, whose first element is a list of FunctionParameter structs
51 : * defining the agg's arguments (both direct and aggregated), and whose second
52 : * element is an Integer node with the number of direct args, or -1 if this
53 : * isn't an ordered-set aggregate.
54 : * "parameters" is a list of DefElem representing the agg's definition clauses.
55 : */
56 : ObjectAddress
57 GIC 449 : DefineAggregate(ParseState *pstate,
58 ECB : List *name,
59 : List *args,
60 : bool oldstyle,
61 : List *parameters,
62 : bool replace)
63 : {
64 : char *aggName;
65 : Oid aggNamespace;
66 : AclResult aclresult;
67 GIC 449 : char aggKind = AGGKIND_NORMAL;
68 CBC 449 : List *transfuncName = NIL;
69 449 : List *finalfuncName = NIL;
70 449 : List *combinefuncName = NIL;
71 449 : List *serialfuncName = NIL;
72 449 : List *deserialfuncName = NIL;
73 449 : List *mtransfuncName = NIL;
74 449 : List *minvtransfuncName = NIL;
75 449 : List *mfinalfuncName = NIL;
76 449 : bool finalfuncExtraArgs = false;
77 449 : bool mfinalfuncExtraArgs = false;
78 449 : char finalfuncModify = 0;
79 449 : char mfinalfuncModify = 0;
80 449 : List *sortoperatorName = NIL;
81 449 : TypeName *baseType = NULL;
82 449 : TypeName *transType = NULL;
83 449 : TypeName *mtransType = NULL;
84 449 : int32 transSpace = 0;
85 449 : int32 mtransSpace = 0;
86 449 : char *initval = NULL;
87 449 : char *minitval = NULL;
88 449 : char *parallel = NULL;
89 ECB : int numArgs;
90 GIC 449 : int numDirectArgs = 0;
91 ECB : oidvector *parameterTypes;
92 : ArrayType *allParameterTypes;
93 : ArrayType *parameterModes;
94 : ArrayType *parameterNames;
95 : List *parameterDefaults;
96 : Oid variadicArgType;
97 : Oid transTypeId;
98 GIC 449 : Oid mtransTypeId = InvalidOid;
99 ECB : char transTypeType;
100 GIC 449 : char mtransTypeType = 0;
101 CBC 449 : char proparallel = PROPARALLEL_UNSAFE;
102 ECB : ListCell *pl;
103 :
104 : /* Convert list of names to a name and namespace */
105 GIC 449 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
106 ECB :
107 : /* Check we have creation rights in target namespace */
108 GNC 449 : aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
109 CBC 449 : if (aclresult != ACLCHECK_OK)
110 LBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
111 UBC 0 : get_namespace_name(aggNamespace));
112 EUB :
113 : /* Deconstruct the output of the aggr_args grammar production */
114 GIC 449 : if (!oldstyle)
115 ECB : {
116 GIC 268 : Assert(list_length(args) == 2);
117 CBC 268 : numDirectArgs = intVal(lsecond(args));
118 268 : if (numDirectArgs >= 0)
119 11 : aggKind = AGGKIND_ORDERED_SET;
120 ECB : else
121 GIC 257 : numDirectArgs = 0;
122 CBC 268 : args = linitial_node(List, args);
123 ECB : }
124 :
125 : /* Examine aggregate's definition clauses */
126 GIC 2216 : foreach(pl, parameters)
127 ECB : {
128 GIC 1767 : DefElem *defel = lfirst_node(DefElem, pl);
129 ECB :
130 : /*
131 : * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
132 : * for sfunc, stype, initcond.
133 : */
134 GIC 1767 : if (strcmp(defel->defname, "sfunc") == 0)
135 CBC 428 : transfuncName = defGetQualifiedName(defel);
136 1339 : else if (strcmp(defel->defname, "sfunc1") == 0)
137 15 : transfuncName = defGetQualifiedName(defel);
138 1324 : else if (strcmp(defel->defname, "finalfunc") == 0)
139 191 : finalfuncName = defGetQualifiedName(defel);
140 1133 : else if (strcmp(defel->defname, "combinefunc") == 0)
141 16 : combinefuncName = defGetQualifiedName(defel);
142 1117 : else if (strcmp(defel->defname, "serialfunc") == 0)
143 18 : serialfuncName = defGetQualifiedName(defel);
144 1099 : else if (strcmp(defel->defname, "deserialfunc") == 0)
145 15 : deserialfuncName = defGetQualifiedName(defel);
146 1084 : else if (strcmp(defel->defname, "msfunc") == 0)
147 30 : mtransfuncName = defGetQualifiedName(defel);
148 1054 : else if (strcmp(defel->defname, "minvfunc") == 0)
149 30 : minvtransfuncName = defGetQualifiedName(defel);
150 1024 : else if (strcmp(defel->defname, "mfinalfunc") == 0)
151 LBC 0 : mfinalfuncName = defGetQualifiedName(defel);
152 GBC 1024 : else if (strcmp(defel->defname, "finalfunc_extra") == 0)
153 CBC 8 : finalfuncExtraArgs = defGetBoolean(defel);
154 1016 : else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
155 LBC 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
156 GBC 1016 : else if (strcmp(defel->defname, "finalfunc_modify") == 0)
157 CBC 10 : finalfuncModify = extractModify(defel);
158 1006 : else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
159 LBC 0 : mfinalfuncModify = extractModify(defel);
160 GBC 1006 : else if (strcmp(defel->defname, "sortop") == 0)
161 CBC 4 : sortoperatorName = defGetQualifiedName(defel);
162 1002 : else if (strcmp(defel->defname, "basetype") == 0)
163 175 : baseType = defGetTypeName(defel);
164 827 : else if (strcmp(defel->defname, "hypothetical") == 0)
165 ECB : {
166 GIC 4 : if (defGetBoolean(defel))
167 ECB : {
168 GIC 4 : if (aggKind == AGGKIND_NORMAL)
169 LBC 0 : ereport(ERROR,
170 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
171 : errmsg("only ordered-set aggregates can be hypothetical")));
172 GIC 4 : aggKind = AGGKIND_HYPOTHETICAL;
173 ECB : }
174 : }
175 GIC 823 : else if (strcmp(defel->defname, "stype") == 0)
176 CBC 428 : transType = defGetTypeName(defel);
177 395 : else if (strcmp(defel->defname, "stype1") == 0)
178 15 : transType = defGetTypeName(defel);
179 380 : else if (strcmp(defel->defname, "sspace") == 0)
180 4 : transSpace = defGetInt32(defel);
181 376 : else if (strcmp(defel->defname, "mstype") == 0)
182 30 : mtransType = defGetTypeName(defel);
183 346 : else if (strcmp(defel->defname, "msspace") == 0)
184 LBC 0 : mtransSpace = defGetInt32(defel);
185 GBC 346 : else if (strcmp(defel->defname, "initcond") == 0)
186 CBC 279 : initval = defGetString(defel);
187 67 : else if (strcmp(defel->defname, "initcond1") == 0)
188 9 : initval = defGetString(defel);
189 58 : else if (strcmp(defel->defname, "minitcond") == 0)
190 8 : minitval = defGetString(defel);
191 50 : else if (strcmp(defel->defname, "parallel") == 0)
192 17 : parallel = defGetString(defel);
193 ECB : else
194 GIC 33 : ereport(WARNING,
195 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
196 : errmsg("aggregate attribute \"%s\" not recognized",
197 : defel->defname)));
198 : }
199 :
200 : /*
201 : * make sure we have our required definitions
202 : */
203 GIC 449 : if (transType == NULL)
204 CBC 6 : ereport(ERROR,
205 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
206 : errmsg("aggregate stype must be specified")));
207 GIC 443 : if (transfuncName == NIL)
208 LBC 0 : ereport(ERROR,
209 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
210 : errmsg("aggregate sfunc must be specified")));
211 :
212 : /*
213 : * if mtransType is given, mtransfuncName and minvtransfuncName must be as
214 : * well; if not, then none of the moving-aggregate options should have
215 : * been given.
216 : */
217 GIC 443 : if (mtransType != NULL)
218 ECB : {
219 GIC 30 : if (mtransfuncName == NIL)
220 LBC 0 : ereport(ERROR,
221 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
222 : errmsg("aggregate msfunc must be specified when mstype is specified")));
223 GIC 30 : if (minvtransfuncName == NIL)
224 LBC 0 : ereport(ERROR,
225 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
226 : errmsg("aggregate minvfunc must be specified when mstype is specified")));
227 : }
228 : else
229 : {
230 GIC 413 : if (mtransfuncName != NIL)
231 LBC 0 : ereport(ERROR,
232 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 : errmsg("aggregate msfunc must not be specified without mstype")));
234 GIC 413 : if (minvtransfuncName != NIL)
235 LBC 0 : ereport(ERROR,
236 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 : errmsg("aggregate minvfunc must not be specified without mstype")));
238 GIC 413 : if (mfinalfuncName != NIL)
239 LBC 0 : ereport(ERROR,
240 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241 : errmsg("aggregate mfinalfunc must not be specified without mstype")));
242 GIC 413 : if (mtransSpace != 0)
243 LBC 0 : ereport(ERROR,
244 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
245 : errmsg("aggregate msspace must not be specified without mstype")));
246 GIC 413 : if (minitval != NULL)
247 LBC 0 : ereport(ERROR,
248 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
249 : errmsg("aggregate minitcond must not be specified without mstype")));
250 : }
251 :
252 : /*
253 : * Default values for modify flags can only be determined once we know the
254 : * aggKind.
255 : */
256 GIC 443 : if (finalfuncModify == 0)
257 CBC 433 : finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
258 443 : if (mfinalfuncModify == 0)
259 443 : mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
260 ECB :
261 : /*
262 : * look up the aggregate's input datatype(s).
263 : */
264 GIC 443 : if (oldstyle)
265 ECB : {
266 : /*
267 : * Old style: use basetype parameter. This supports aggregates of
268 : * zero or one input, with input type ANY meaning zero inputs.
269 : *
270 : * Historically we allowed the command to look like basetype = 'ANY'
271 : * so we must do a case-insensitive comparison for the name ANY. Ugh.
272 : */
273 : Oid aggArgTypes[1];
274 :
275 GIC 178 : if (baseType == NULL)
276 CBC 3 : ereport(ERROR,
277 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
278 : errmsg("aggregate input type must be specified")));
279 :
280 GIC 175 : if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
281 ECB : {
282 GIC 3 : numArgs = 0;
283 CBC 3 : aggArgTypes[0] = InvalidOid;
284 ECB : }
285 : else
286 : {
287 GIC 172 : numArgs = 1;
288 CBC 172 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
289 ECB : }
290 GIC 175 : parameterTypes = buildoidvector(aggArgTypes, numArgs);
291 CBC 175 : allParameterTypes = NULL;
292 175 : parameterModes = NULL;
293 175 : parameterNames = NULL;
294 175 : parameterDefaults = NIL;
295 175 : variadicArgType = InvalidOid;
296 ECB : }
297 : else
298 : {
299 : /*
300 : * New style: args is a list of FunctionParameters (possibly zero of
301 : * 'em). We share functioncmds.c's code for processing them.
302 : */
303 : Oid requiredResultType;
304 :
305 GIC 265 : if (baseType != NULL)
306 LBC 0 : ereport(ERROR,
307 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
308 : errmsg("basetype is redundant with aggregate input type specification")));
309 :
310 GIC 265 : numArgs = list_length(args);
311 CBC 265 : interpret_function_parameter_list(pstate,
312 ECB : args,
313 : InvalidOid,
314 : OBJECT_AGGREGATE,
315 : ¶meterTypes,
316 : NULL,
317 : &allParameterTypes,
318 : ¶meterModes,
319 : ¶meterNames,
320 : NULL,
321 : ¶meterDefaults,
322 : &variadicArgType,
323 : &requiredResultType);
324 : /* Parameter defaults are not currently allowed by the grammar */
325 GIC 262 : Assert(parameterDefaults == NIL);
326 ECB : /* There shouldn't have been any OUT parameters, either */
327 GIC 262 : Assert(requiredResultType == InvalidOid);
328 ECB : }
329 :
330 : /*
331 : * look up the aggregate's transtype.
332 : *
333 : * transtype can't be a pseudo-type, since we need to be able to store
334 : * values of the transtype. However, we can allow polymorphic transtype
335 : * in some cases (AggregateCreate will check). Also, we allow "internal"
336 : * for functions that want to pass pointers to private data structures;
337 : * but allow that only to superusers, since you could crash the system (or
338 : * worse) by connecting up incompatible internal-using functions in an
339 : * aggregate.
340 : */
341 GIC 437 : transTypeId = typenameTypeId(NULL, transType);
342 CBC 437 : transTypeType = get_typtype(transTypeId);
343 437 : if (transTypeType == TYPTYPE_PSEUDO &&
344 137 : !IsPolymorphicType(transTypeId))
345 ECB : {
346 GIC 29 : if (transTypeId == INTERNALOID && superuser())
347 ECB : /* okay */ ;
348 : else
349 UIC 0 : ereport(ERROR,
350 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351 : errmsg("aggregate transition data type cannot be %s",
352 : format_type_be(transTypeId))));
353 : }
354 :
355 GIC 437 : if (serialfuncName && deserialfuncName)
356 ECB : {
357 : /*
358 : * Serialization is only needed/allowed for transtype INTERNAL.
359 : */
360 GIC 15 : if (transTypeId != INTERNALOID)
361 LBC 0 : ereport(ERROR,
362 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
363 : errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
364 : format_type_be(INTERNALOID))));
365 : }
366 GIC 422 : else if (serialfuncName || deserialfuncName)
367 ECB : {
368 : /*
369 : * Cannot specify one function without the other.
370 : */
371 GIC 3 : ereport(ERROR,
372 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
373 : errmsg("must specify both or neither of serialization and deserialization functions")));
374 : }
375 :
376 : /*
377 : * If a moving-aggregate transtype is specified, look that up. Same
378 : * restrictions as for transtype.
379 : */
380 GIC 434 : if (mtransType)
381 ECB : {
382 GIC 30 : mtransTypeId = typenameTypeId(NULL, mtransType);
383 CBC 30 : mtransTypeType = get_typtype(mtransTypeId);
384 30 : if (mtransTypeType == TYPTYPE_PSEUDO &&
385 LBC 0 : !IsPolymorphicType(mtransTypeId))
386 EUB : {
387 UIC 0 : if (mtransTypeId == INTERNALOID && superuser())
388 EUB : /* okay */ ;
389 : else
390 UIC 0 : ereport(ERROR,
391 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
392 : errmsg("aggregate transition data type cannot be %s",
393 : format_type_be(mtransTypeId))));
394 : }
395 : }
396 :
397 : /*
398 : * If we have an initval, and it's not for a pseudotype (particularly a
399 : * polymorphic type), make sure it's acceptable to the type's input
400 : * function. We will store the initval as text, because the input
401 : * function isn't necessarily immutable (consider "now" for timestamp),
402 : * and we want to use the runtime not creation-time interpretation of the
403 : * value. However, if it's an incorrect value it seems much more
404 : * user-friendly to complain at CREATE AGGREGATE time.
405 : */
406 GIC 434 : if (initval && transTypeType != TYPTYPE_PSEUDO)
407 ECB : {
408 : Oid typinput,
409 : typioparam;
410 :
411 GIC 185 : getTypeInputInfo(transTypeId, &typinput, &typioparam);
412 CBC 185 : (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
413 ECB : }
414 :
415 : /*
416 : * Likewise for moving-aggregate initval.
417 : */
418 GIC 434 : if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
419 ECB : {
420 : Oid typinput,
421 : typioparam;
422 :
423 GIC 8 : getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
424 CBC 8 : (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
425 ECB : }
426 :
427 GIC 434 : if (parallel)
428 ECB : {
429 GIC 17 : if (strcmp(parallel, "safe") == 0)
430 CBC 14 : proparallel = PROPARALLEL_SAFE;
431 3 : else if (strcmp(parallel, "restricted") == 0)
432 LBC 0 : proparallel = PROPARALLEL_RESTRICTED;
433 GBC 3 : else if (strcmp(parallel, "unsafe") == 0)
434 LBC 0 : proparallel = PROPARALLEL_UNSAFE;
435 EUB : else
436 GIC 3 : ereport(ERROR,
437 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
438 : errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
439 : }
440 :
441 : /*
442 : * Most of the argument-checking is done inside of AggregateCreate
443 : */
444 GIC 431 : return AggregateCreate(aggName, /* aggregate name */
445 ECB : aggNamespace, /* namespace */
446 : replace,
447 : aggKind,
448 : numArgs,
449 : numDirectArgs,
450 : parameterTypes,
451 : PointerGetDatum(allParameterTypes),
452 : PointerGetDatum(parameterModes),
453 : PointerGetDatum(parameterNames),
454 : parameterDefaults,
455 : variadicArgType,
456 : transfuncName, /* step function name */
457 : finalfuncName, /* final function name */
458 : combinefuncName, /* combine function name */
459 : serialfuncName, /* serial function name */
460 : deserialfuncName, /* deserial function name */
461 : mtransfuncName, /* fwd trans function name */
462 : minvtransfuncName, /* inv trans function name */
463 : mfinalfuncName, /* final function name */
464 : finalfuncExtraArgs,
465 : mfinalfuncExtraArgs,
466 : finalfuncModify,
467 : mfinalfuncModify,
468 : sortoperatorName, /* sort operator name */
469 : transTypeId, /* transition data type */
470 : transSpace, /* transition space */
471 : mtransTypeId, /* transition data type */
472 : mtransSpace, /* transition space */
473 : initval, /* initial condition */
474 : minitval, /* initial condition */
475 : proparallel); /* parallel safe? */
476 : }
477 :
478 : /*
479 : * Convert the string form of [m]finalfunc_modify to the catalog representation
480 : */
481 : static char
482 GIC 10 : extractModify(DefElem *defel)
483 ECB : {
484 GIC 10 : char *val = defGetString(defel);
485 ECB :
486 GIC 10 : if (strcmp(val, "read_only") == 0)
487 LBC 0 : return AGGMODIFY_READ_ONLY;
488 GBC 10 : if (strcmp(val, "shareable") == 0)
489 CBC 7 : return AGGMODIFY_SHAREABLE;
490 3 : if (strcmp(val, "read_write") == 0)
491 3 : return AGGMODIFY_READ_WRITE;
492 LBC 0 : ereport(ERROR,
493 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
494 : errmsg("parameter \"%s\" must be READ_ONLY, SHAREABLE, or READ_WRITE",
495 : defel->defname)));
496 : return 0; /* keep compiler quiet */
497 : }
|