Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * aggregatecmds.c
4 : *
5 : * Routines for aggregate-manipulation commands
6 : *
7 : * Portions Copyright (c) 1996-2017, 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/indexing.h"
28 : #include "catalog/pg_aggregate.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 : /*
43 : * DefineAggregate
44 : *
45 : * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
46 : * is specified by a BASETYPE element in the parameters. Otherwise,
47 : * "args" is a pair, whose first element is a list of FunctionParameter structs
48 : * defining the agg's arguments (both direct and aggregated), and whose second
49 : * element is an Integer node with the number of direct args, or -1 if this
50 : * isn't an ordered-set aggregate.
51 : * "parameters" is a list of DefElem representing the agg's definition clauses.
52 : */
53 : ObjectAddress
54 119 : DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters)
55 : {
56 : char *aggName;
57 : Oid aggNamespace;
58 : AclResult aclresult;
59 119 : char aggKind = AGGKIND_NORMAL;
60 119 : List *transfuncName = NIL;
61 119 : List *finalfuncName = NIL;
62 119 : List *combinefuncName = NIL;
63 119 : List *serialfuncName = NIL;
64 119 : List *deserialfuncName = NIL;
65 119 : List *mtransfuncName = NIL;
66 119 : List *minvtransfuncName = NIL;
67 119 : List *mfinalfuncName = NIL;
68 119 : bool finalfuncExtraArgs = false;
69 119 : bool mfinalfuncExtraArgs = false;
70 119 : List *sortoperatorName = NIL;
71 119 : TypeName *baseType = NULL;
72 119 : TypeName *transType = NULL;
73 119 : TypeName *mtransType = NULL;
74 119 : int32 transSpace = 0;
75 119 : int32 mtransSpace = 0;
76 119 : char *initval = NULL;
77 119 : char *minitval = NULL;
78 119 : char *parallel = NULL;
79 : int numArgs;
80 119 : 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 119 : Oid mtransTypeId = InvalidOid;
89 : char transTypeType;
90 119 : char mtransTypeType = 0;
91 119 : char proparallel = PROPARALLEL_UNSAFE;
92 : ListCell *pl;
93 :
94 : /* Convert list of names to a name and namespace */
95 119 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
96 :
97 : /* Check we have creation rights in target namespace */
98 119 : aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
99 119 : if (aclresult != ACLCHECK_OK)
100 0 : aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
101 0 : get_namespace_name(aggNamespace));
102 :
103 : /* Deconstruct the output of the aggr_args grammar production */
104 119 : if (!oldstyle)
105 : {
106 61 : Assert(list_length(args) == 2);
107 61 : numDirectArgs = intVal(lsecond(args));
108 61 : if (numDirectArgs >= 0)
109 2 : aggKind = AGGKIND_ORDERED_SET;
110 : else
111 59 : numDirectArgs = 0;
112 61 : args = linitial_node(List, args);
113 : }
114 :
115 : /* Examine aggregate's definition clauses */
116 591 : foreach(pl, parameters)
117 : {
118 472 : 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 472 : if (pg_strcasecmp(defel->defname, "sfunc") == 0)
125 114 : transfuncName = defGetQualifiedName(defel);
126 358 : else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
127 5 : transfuncName = defGetQualifiedName(defel);
128 353 : else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
129 53 : finalfuncName = defGetQualifiedName(defel);
130 300 : else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
131 2 : combinefuncName = defGetQualifiedName(defel);
132 298 : else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
133 5 : serialfuncName = defGetQualifiedName(defel);
134 293 : else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
135 4 : deserialfuncName = defGetQualifiedName(defel);
136 289 : else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
137 8 : mtransfuncName = defGetQualifiedName(defel);
138 281 : else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
139 8 : minvtransfuncName = defGetQualifiedName(defel);
140 273 : else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
141 0 : mfinalfuncName = defGetQualifiedName(defel);
142 273 : else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
143 2 : finalfuncExtraArgs = defGetBoolean(defel);
144 271 : else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
145 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
146 271 : else if (pg_strcasecmp(defel->defname, "sortop") == 0)
147 0 : sortoperatorName = defGetQualifiedName(defel);
148 271 : else if (pg_strcasecmp(defel->defname, "basetype") == 0)
149 57 : baseType = defGetTypeName(defel);
150 214 : else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
151 : {
152 1 : if (defGetBoolean(defel))
153 : {
154 1 : if (aggKind == AGGKIND_NORMAL)
155 0 : ereport(ERROR,
156 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
157 : errmsg("only ordered-set aggregates can be hypothetical")));
158 1 : aggKind = AGGKIND_HYPOTHETICAL;
159 : }
160 : }
161 213 : else if (pg_strcasecmp(defel->defname, "stype") == 0)
162 114 : transType = defGetTypeName(defel);
163 99 : else if (pg_strcasecmp(defel->defname, "stype1") == 0)
164 5 : transType = defGetTypeName(defel);
165 94 : else if (pg_strcasecmp(defel->defname, "sspace") == 0)
166 1 : transSpace = defGetInt32(defel);
167 93 : else if (pg_strcasecmp(defel->defname, "mstype") == 0)
168 8 : mtransType = defGetTypeName(defel);
169 85 : else if (pg_strcasecmp(defel->defname, "msspace") == 0)
170 0 : mtransSpace = defGetInt32(defel);
171 85 : else if (pg_strcasecmp(defel->defname, "initcond") == 0)
172 79 : initval = defGetString(defel);
173 6 : else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
174 2 : initval = defGetString(defel);
175 4 : else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
176 2 : minitval = defGetString(defel);
177 2 : else if (pg_strcasecmp(defel->defname, "parallel") == 0)
178 2 : parallel = defGetString(defel);
179 : else
180 0 : ereport(WARNING,
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 119 : if (transType == NULL)
190 0 : ereport(ERROR,
191 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
192 : errmsg("aggregate stype must be specified")));
193 119 : if (transfuncName == NIL)
194 0 : 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 119 : if (mtransType != NULL)
204 : {
205 8 : if (mtransfuncName == NIL)
206 0 : ereport(ERROR,
207 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
208 : errmsg("aggregate msfunc must be specified when mstype is specified")));
209 8 : if (minvtransfuncName == NIL)
210 0 : ereport(ERROR,
211 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
212 : errmsg("aggregate minvfunc must be specified when mstype is specified")));
213 : }
214 : else
215 : {
216 111 : if (mtransfuncName != NIL)
217 0 : ereport(ERROR,
218 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
219 : errmsg("aggregate msfunc must not be specified without mstype")));
220 111 : if (minvtransfuncName != NIL)
221 0 : ereport(ERROR,
222 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
223 : errmsg("aggregate minvfunc must not be specified without mstype")));
224 111 : if (mfinalfuncName != NIL)
225 0 : ereport(ERROR,
226 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
227 : errmsg("aggregate mfinalfunc must not be specified without mstype")));
228 111 : if (mtransSpace != 0)
229 0 : ereport(ERROR,
230 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
231 : errmsg("aggregate msspace must not be specified without mstype")));
232 111 : if (minitval != NULL)
233 0 : 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 119 : 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 58 : if (baseType == NULL)
253 1 : ereport(ERROR,
254 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
255 : errmsg("aggregate input type must be specified")));
256 :
257 57 : if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
258 : {
259 1 : numArgs = 0;
260 1 : aggArgTypes[0] = InvalidOid;
261 : }
262 : else
263 : {
264 56 : numArgs = 1;
265 56 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
266 : }
267 57 : parameterTypes = buildoidvector(aggArgTypes, numArgs);
268 57 : allParameterTypes = NULL;
269 57 : parameterModes = NULL;
270 57 : parameterNames = NULL;
271 57 : parameterDefaults = NIL;
272 57 : 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 61 : if (baseType != NULL)
283 0 : ereport(ERROR,
284 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
285 : errmsg("basetype is redundant with aggregate input type specification")));
286 :
287 61 : numArgs = list_length(args);
288 61 : interpret_function_parameter_list(pstate,
289 : args,
290 : InvalidOid,
291 : true, /* is an aggregate */
292 : ¶meterTypes,
293 : &allParameterTypes,
294 : ¶meterModes,
295 : ¶meterNames,
296 : ¶meterDefaults,
297 : &variadicArgType,
298 : &requiredResultType);
299 : /* Parameter defaults are not currently allowed by the grammar */
300 60 : Assert(parameterDefaults == NIL);
301 : /* There shouldn't have been any OUT parameters, either */
302 60 : 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 117 : transTypeId = typenameTypeId(NULL, transType);
317 117 : transTypeType = get_typtype(transTypeId);
318 117 : if (transTypeType == TYPTYPE_PSEUDO &&
319 40 : !IsPolymorphicType(transTypeId))
320 : {
321 7 : if (transTypeId == INTERNALOID && superuser())
322 : /* okay */ ;
323 : else
324 0 : 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 117 : if (serialfuncName && deserialfuncName)
331 : {
332 : /*
333 : * Serialization is only needed/allowed for transtype INTERNAL.
334 : */
335 8 : if (transTypeId != INTERNALOID)
336 0 : ereport(ERROR,
337 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
338 : errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
339 : format_type_be(INTERNALOID))));
340 : }
341 113 : else if (serialfuncName || deserialfuncName)
342 : {
343 : /*
344 : * Cannot specify one function without the other.
345 : */
346 1 : 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 116 : if (mtransType)
356 : {
357 8 : mtransTypeId = typenameTypeId(NULL, mtransType);
358 8 : mtransTypeType = get_typtype(mtransTypeId);
359 8 : if (mtransTypeType == TYPTYPE_PSEUDO &&
360 0 : !IsPolymorphicType(mtransTypeId))
361 : {
362 0 : if (mtransTypeId == INTERNALOID && superuser())
363 : /* okay */ ;
364 : else
365 0 : 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 116 : if (initval && transTypeType != TYPTYPE_PSEUDO)
382 : {
383 : Oid typinput,
384 : typioparam;
385 :
386 48 : getTypeInputInfo(transTypeId, &typinput, &typioparam);
387 48 : (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
388 : }
389 :
390 : /*
391 : * Likewise for moving-aggregate initval.
392 : */
393 116 : if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
394 : {
395 : Oid typinput,
396 : typioparam;
397 :
398 2 : getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
399 2 : (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
400 : }
401 :
402 116 : if (parallel)
403 : {
404 2 : if (pg_strcasecmp(parallel, "safe") == 0)
405 1 : proparallel = PROPARALLEL_SAFE;
406 1 : else if (pg_strcasecmp(parallel, "restricted") == 0)
407 0 : proparallel = PROPARALLEL_RESTRICTED;
408 1 : else if (pg_strcasecmp(parallel, "unsafe") == 0)
409 0 : proparallel = PROPARALLEL_UNSAFE;
410 : else
411 1 : 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 115 : 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 : }
|