Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * aggregatecmds.c
4 : : *
5 : : * Routines for aggregate-manipulation commands
6 : : *
7 : : * Portions Copyright (c) 1996-2025, 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"
26 : : #include "catalog/pg_aggregate.h"
27 : : #include "catalog/pg_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 : :
38 : : static 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 : : */
52 : : ObjectAddress
2363 rhodiumtoad@postgres 53 :CBC 453 : DefineAggregate(ParseState *pstate,
54 : : List *name,
55 : : List *args,
56 : : bool oldstyle,
57 : : List *parameters,
58 : : bool replace)
59 : : {
60 : : char *aggName;
61 : : Oid aggNamespace;
62 : : AclResult aclresult;
4275 tgl@sss.pgh.pa.us 63 : 453 : char aggKind = AGGKIND_NORMAL;
8545 64 : 453 : List *transfuncName = NIL;
65 : 453 : List *finalfuncName = NIL;
3517 rhaas@postgresql.org 66 : 453 : List *combinefuncName = NIL;
3448 67 : 453 : List *serialfuncName = NIL;
68 : 453 : List *deserialfuncName = NIL;
4165 tgl@sss.pgh.pa.us 69 : 453 : List *mtransfuncName = NIL;
70 : 453 : List *minvtransfuncName = NIL;
71 : 453 : List *mfinalfuncName = NIL;
4154 72 : 453 : bool finalfuncExtraArgs = false;
73 : 453 : bool mfinalfuncExtraArgs = false;
2884 74 : 453 : char finalfuncModify = 0;
75 : 453 : char mfinalfuncModify = 0;
7452 76 : 453 : List *sortoperatorName = NIL;
8545 77 : 453 : TypeName *baseType = NULL;
78 : 453 : TypeName *transType = NULL;
4165 79 : 453 : TypeName *mtransType = NULL;
4312 80 : 453 : int32 transSpace = 0;
4165 81 : 453 : int32 mtransSpace = 0;
8545 82 : 453 : char *initval = NULL;
4165 83 : 453 : char *minitval = NULL;
3441 rhaas@postgresql.org 84 : 453 : char *parallel = NULL;
85 : : int numArgs;
4275 tgl@sss.pgh.pa.us 86 : 453 : int numDirectArgs = 0;
87 : : oidvector *parameterTypes;
88 : : ArrayType *allParameterTypes;
89 : : ArrayType *parameterModes;
90 : : ArrayType *parameterNames;
91 : : List *parameterDefaults;
92 : : Oid variadicArgType;
93 : : Oid transTypeId;
4165 94 : 453 : Oid mtransTypeId = InvalidOid;
95 : : char transTypeType;
96 : 453 : char mtransTypeType = 0;
3441 rhaas@postgresql.org 97 : 453 : char proparallel = PROPARALLEL_UNSAFE;
98 : : ListCell *pl;
99 : :
100 : : /* Convert list of names to a name and namespace */
7084 tgl@sss.pgh.pa.us 101 : 453 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
102 : :
103 : : /* Check we have creation rights in target namespace */
1028 peter@eisentraut.org 104 : 453 : aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
8533 tgl@sss.pgh.pa.us 105 [ - + ]: 453 : if (aclresult != ACLCHECK_OK)
2835 peter_e@gmx.net 106 :UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
8072 tgl@sss.pgh.pa.us 107 : 0 : get_namespace_name(aggNamespace));
108 : :
109 : : /* Deconstruct the output of the aggr_args grammar production */
4275 tgl@sss.pgh.pa.us 110 [ + + ]:CBC 453 : if (!oldstyle)
111 : : {
112 [ - + ]: 272 : Assert(list_length(args) == 2);
113 : 272 : numDirectArgs = intVal(lsecond(args));
114 [ + + ]: 272 : if (numDirectArgs >= 0)
115 : 11 : aggKind = AGGKIND_ORDERED_SET;
116 : : else
117 : 261 : numDirectArgs = 0;
3071 118 : 272 : args = linitial_node(List, args);
119 : : }
120 : :
121 : : /* Examine aggregate's definition clauses */
8545 122 [ + - + + : 2231 : foreach(pl, parameters)
+ + ]
123 : : {
3071 124 : 1778 : DefElem *defel = lfirst_node(DefElem, pl);
125 : :
126 : : /*
127 : : * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
128 : : * for sfunc, stype, initcond.
129 : : */
2780 130 [ + + ]: 1778 : if (strcmp(defel->defname, "sfunc") == 0)
8545 131 : 432 : transfuncName = defGetQualifiedName(defel);
2780 132 [ + + ]: 1346 : else if (strcmp(defel->defname, "sfunc1") == 0)
8545 133 : 15 : transfuncName = defGetQualifiedName(defel);
2780 134 [ + + ]: 1331 : else if (strcmp(defel->defname, "finalfunc") == 0)
8545 135 : 194 : finalfuncName = defGetQualifiedName(defel);
2780 136 [ + + ]: 1137 : else if (strcmp(defel->defname, "combinefunc") == 0)
3517 rhaas@postgresql.org 137 : 16 : combinefuncName = defGetQualifiedName(defel);
2780 tgl@sss.pgh.pa.us 138 [ + + ]: 1121 : else if (strcmp(defel->defname, "serialfunc") == 0)
3448 rhaas@postgresql.org 139 : 18 : serialfuncName = defGetQualifiedName(defel);
2780 tgl@sss.pgh.pa.us 140 [ + + ]: 1103 : else if (strcmp(defel->defname, "deserialfunc") == 0)
3448 rhaas@postgresql.org 141 : 15 : deserialfuncName = defGetQualifiedName(defel);
2780 tgl@sss.pgh.pa.us 142 [ + + ]: 1088 : else if (strcmp(defel->defname, "msfunc") == 0)
4165 143 : 30 : mtransfuncName = defGetQualifiedName(defel);
2780 144 [ + + ]: 1058 : else if (strcmp(defel->defname, "minvfunc") == 0)
4165 145 : 30 : minvtransfuncName = defGetQualifiedName(defel);
2780 146 [ - + ]: 1028 : else if (strcmp(defel->defname, "mfinalfunc") == 0)
4165 tgl@sss.pgh.pa.us 147 :UBC 0 : mfinalfuncName = defGetQualifiedName(defel);
2780 tgl@sss.pgh.pa.us 148 [ + + ]:CBC 1028 : else if (strcmp(defel->defname, "finalfunc_extra") == 0)
4154 149 : 8 : finalfuncExtraArgs = defGetBoolean(defel);
2780 150 [ - + ]: 1020 : else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
4154 tgl@sss.pgh.pa.us 151 :UBC 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
2780 tgl@sss.pgh.pa.us 152 [ + + ]:CBC 1020 : else if (strcmp(defel->defname, "finalfunc_modify") == 0)
2884 153 : 10 : finalfuncModify = extractModify(defel);
2780 154 [ - + ]: 1010 : else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
2884 tgl@sss.pgh.pa.us 155 :UBC 0 : mfinalfuncModify = extractModify(defel);
2780 tgl@sss.pgh.pa.us 156 [ + + ]:CBC 1010 : else if (strcmp(defel->defname, "sortop") == 0)
7452 157 : 4 : sortoperatorName = defGetQualifiedName(defel);
2780 158 [ + + ]: 1006 : else if (strcmp(defel->defname, "basetype") == 0)
8545 159 : 175 : baseType = defGetTypeName(defel);
2780 160 [ + + ]: 831 : else if (strcmp(defel->defname, "hypothetical") == 0)
161 : : {
4275 162 [ + - ]: 4 : if (defGetBoolean(defel))
163 : : {
164 [ - + ]: 4 : if (aggKind == AGGKIND_NORMAL)
4275 tgl@sss.pgh.pa.us 165 [ # # ]:UBC 0 : ereport(ERROR,
166 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
167 : : errmsg("only ordered-set aggregates can be hypothetical")));
4275 tgl@sss.pgh.pa.us 168 :CBC 4 : aggKind = AGGKIND_HYPOTHETICAL;
169 : : }
170 : : }
2780 171 [ + + ]: 827 : else if (strcmp(defel->defname, "stype") == 0)
8545 172 : 432 : transType = defGetTypeName(defel);
2780 173 [ + + ]: 395 : else if (strcmp(defel->defname, "stype1") == 0)
8545 174 : 15 : transType = defGetTypeName(defel);
2780 175 [ + + ]: 380 : else if (strcmp(defel->defname, "sspace") == 0)
4312 176 : 4 : transSpace = defGetInt32(defel);
2780 177 [ + + ]: 376 : else if (strcmp(defel->defname, "mstype") == 0)
4165 178 : 30 : mtransType = defGetTypeName(defel);
2780 179 [ - + ]: 346 : else if (strcmp(defel->defname, "msspace") == 0)
4165 tgl@sss.pgh.pa.us 180 :UBC 0 : mtransSpace = defGetInt32(defel);
2780 tgl@sss.pgh.pa.us 181 [ + + ]:CBC 346 : else if (strcmp(defel->defname, "initcond") == 0)
8545 182 : 279 : initval = defGetString(defel);
2780 183 [ + + ]: 67 : else if (strcmp(defel->defname, "initcond1") == 0)
8545 184 : 9 : initval = defGetString(defel);
2780 185 [ + + ]: 58 : else if (strcmp(defel->defname, "minitcond") == 0)
4165 186 : 8 : minitval = defGetString(defel);
2780 187 [ + + ]: 50 : else if (strcmp(defel->defname, "parallel") == 0)
3441 rhaas@postgresql.org 188 : 17 : parallel = defGetString(defel);
189 : : else
8084 tgl@sss.pgh.pa.us 190 [ + - ]: 33 : ereport(WARNING,
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 : : */
8545 199 [ + + ]: 453 : if (transType == NULL)
8084 200 [ + - ]: 6 : ereport(ERROR,
201 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
202 : : errmsg("aggregate stype must be specified")));
8545 203 [ - + ]: 447 : if (transfuncName == NIL)
8084 tgl@sss.pgh.pa.us 204 [ # # ]:UBC 0 : ereport(ERROR,
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 : : */
4165 tgl@sss.pgh.pa.us 213 [ + + ]:CBC 447 : if (mtransType != NULL)
214 : : {
215 [ - + ]: 30 : if (mtransfuncName == NIL)
4165 tgl@sss.pgh.pa.us 216 [ # # ]:UBC 0 : ereport(ERROR,
217 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
218 : : errmsg("aggregate msfunc must be specified when mstype is specified")));
4165 tgl@sss.pgh.pa.us 219 [ - + ]:CBC 30 : if (minvtransfuncName == NIL)
4165 tgl@sss.pgh.pa.us 220 [ # # ]:UBC 0 : ereport(ERROR,
221 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
222 : : errmsg("aggregate minvfunc must be specified when mstype is specified")));
223 : : }
224 : : else
225 : : {
4165 tgl@sss.pgh.pa.us 226 [ - + ]:CBC 417 : if (mtransfuncName != NIL)
4165 tgl@sss.pgh.pa.us 227 [ # # ]:UBC 0 : ereport(ERROR,
228 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229 : : errmsg("aggregate msfunc must not be specified without mstype")));
4165 tgl@sss.pgh.pa.us 230 [ - + ]:CBC 417 : if (minvtransfuncName != NIL)
4165 tgl@sss.pgh.pa.us 231 [ # # ]:UBC 0 : ereport(ERROR,
232 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 : : errmsg("aggregate minvfunc must not be specified without mstype")));
4165 tgl@sss.pgh.pa.us 234 [ - + ]:CBC 417 : if (mfinalfuncName != NIL)
4165 tgl@sss.pgh.pa.us 235 [ # # ]:UBC 0 : ereport(ERROR,
236 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 : : errmsg("aggregate mfinalfunc must not be specified without mstype")));
4165 tgl@sss.pgh.pa.us 238 [ - + ]:CBC 417 : if (mtransSpace != 0)
4165 tgl@sss.pgh.pa.us 239 [ # # ]:UBC 0 : ereport(ERROR,
240 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241 : : errmsg("aggregate msspace must not be specified without mstype")));
4165 tgl@sss.pgh.pa.us 242 [ - + ]:CBC 417 : if (minitval != NULL)
4165 tgl@sss.pgh.pa.us 243 [ # # ]:UBC 0 : ereport(ERROR,
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 : : */
2884 tgl@sss.pgh.pa.us 252 [ + + ]:CBC 447 : if (finalfuncModify == 0)
253 [ + + ]: 437 : finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
254 [ + - ]: 447 : if (mfinalfuncModify == 0)
255 [ + + ]: 447 : mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
256 : :
257 : : /*
258 : : * look up the aggregate's input datatype(s).
259 : : */
7084 260 [ + + ]: 447 : 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 [ + + ]: 178 : if (baseType == NULL)
272 [ + - ]: 3 : ereport(ERROR,
273 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
274 : : errmsg("aggregate input type must be specified")));
275 : :
276 [ + + ]: 175 : if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
277 : : {
6981 278 : 3 : numArgs = 0;
4386 279 : 3 : aggArgTypes[0] = InvalidOid;
280 : : }
281 : : else
282 : : {
6981 283 : 172 : numArgs = 1;
5430 peter_e@gmx.net 284 : 172 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
285 : : }
4386 tgl@sss.pgh.pa.us 286 : 175 : parameterTypes = buildoidvector(aggArgTypes, numArgs);
287 : 175 : allParameterTypes = NULL;
288 : 175 : parameterModes = NULL;
289 : 175 : parameterNames = NULL;
290 : 175 : parameterDefaults = NIL;
4275 291 : 175 : 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 : :
7084 301 [ - + ]: 269 : if (baseType != NULL)
7084 tgl@sss.pgh.pa.us 302 [ # # ]:UBC 0 : ereport(ERROR,
303 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
304 : : errmsg("basetype is redundant with aggregate input type specification")));
305 : :
6981 tgl@sss.pgh.pa.us 306 :CBC 269 : numArgs = list_length(args);
3287 peter_e@gmx.net 307 : 269 : interpret_function_parameter_list(pstate,
308 : : args,
309 : : InvalidOid,
310 : : OBJECT_AGGREGATE,
311 : : ¶meterTypes,
312 : : NULL,
313 : : &allParameterTypes,
314 : : ¶meterModes,
315 : : ¶meterNames,
316 : : NULL,
317 : : ¶meterDefaults,
318 : : &variadicArgType,
319 : : &requiredResultType);
320 : : /* Parameter defaults are not currently allowed by the grammar */
4386 tgl@sss.pgh.pa.us 321 [ - + ]: 266 : Assert(parameterDefaults == NIL);
322 : : /* There shouldn't have been any OUT parameters, either */
323 [ - + ]: 266 : 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 : : */
5430 peter_e@gmx.net 337 : 441 : transTypeId = typenameTypeId(NULL, transType);
4720 tgl@sss.pgh.pa.us 338 : 441 : transTypeType = get_typtype(transTypeId);
339 [ + + + + ]: 441 : if (transTypeType == TYPTYPE_PSEUDO &&
6732 340 [ + + + - : 140 : !IsPolymorphicType(transTypeId))
+ - + - +
- + + + -
+ - + - +
- ]
341 : : {
6140 342 [ + - + - ]: 29 : if (transTypeId == INTERNALOID && superuser())
343 : : /* okay */ ;
344 : : else
6140 tgl@sss.pgh.pa.us 345 [ # # ]:UBC 0 : ereport(ERROR,
346 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
347 : : errmsg("aggregate transition data type cannot be %s",
348 : : format_type_be(transTypeId))));
349 : : }
350 : :
3363 tgl@sss.pgh.pa.us 351 [ + + + + ]:CBC 441 : if (serialfuncName && deserialfuncName)
352 : : {
353 : : /*
354 : : * Serialization is only needed/allowed for transtype INTERNAL.
355 : : */
3448 rhaas@postgresql.org 356 [ - + ]: 15 : if (transTypeId != INTERNALOID)
3448 rhaas@postgresql.org 357 [ # # ]:UBC 0 : ereport(ERROR,
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 : : }
3363 tgl@sss.pgh.pa.us 362 [ + + - + ]:CBC 426 : else if (serialfuncName || deserialfuncName)
363 : : {
364 : : /*
365 : : * Cannot specify one function without the other.
366 : : */
367 [ + - ]: 3 : ereport(ERROR,
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 : : */
4165 376 [ + + ]: 438 : if (mtransType)
377 : : {
378 : 30 : mtransTypeId = typenameTypeId(NULL, mtransType);
379 : 30 : mtransTypeType = get_typtype(mtransTypeId);
380 [ - + - - ]: 30 : if (mtransTypeType == TYPTYPE_PSEUDO &&
4165 tgl@sss.pgh.pa.us 381 [ # # # # :UBC 0 : !IsPolymorphicType(mtransTypeId))
# # # # #
# # # # #
# # # # #
# ]
382 : : {
383 [ # # # # ]: 0 : if (mtransTypeId == INTERNALOID && superuser())
384 : : /* okay */ ;
385 : : else
386 [ # # ]: 0 : ereport(ERROR,
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 : : */
4720 tgl@sss.pgh.pa.us 402 [ + + + + ]:CBC 438 : if (initval && transTypeType != TYPTYPE_PSEUDO)
403 : : {
404 : : Oid typinput,
405 : : typioparam;
406 : :
407 : 185 : getTypeInputInfo(transTypeId, &typinput, &typioparam);
408 : 185 : (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
409 : : }
410 : :
411 : : /*
412 : : * Likewise for moving-aggregate initval.
413 : : */
4165 414 [ + + + - ]: 438 : if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
415 : : {
416 : : Oid typinput,
417 : : typioparam;
418 : :
419 : 8 : getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
420 : 8 : (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
421 : : }
422 : :
3441 rhaas@postgresql.org 423 [ + + ]: 438 : if (parallel)
424 : : {
2780 tgl@sss.pgh.pa.us 425 [ + + ]: 17 : if (strcmp(parallel, "safe") == 0)
3441 rhaas@postgresql.org 426 : 14 : proparallel = PROPARALLEL_SAFE;
2780 tgl@sss.pgh.pa.us 427 [ - + ]: 3 : else if (strcmp(parallel, "restricted") == 0)
3441 rhaas@postgresql.org 428 :UBC 0 : proparallel = PROPARALLEL_RESTRICTED;
2780 tgl@sss.pgh.pa.us 429 [ - + ]:CBC 3 : else if (strcmp(parallel, "unsafe") == 0)
3441 rhaas@postgresql.org 430 :UBC 0 : proparallel = PROPARALLEL_UNSAFE;
431 : : else
3441 rhaas@postgresql.org 432 [ + - ]:CBC 3 : ereport(ERROR,
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 : : */
2999 tgl@sss.pgh.pa.us 440 : 435 : 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 : : }
473 : :
474 : : /*
475 : : * Convert the string form of [m]finalfunc_modify to the catalog representation
476 : : */
477 : : static char
2884 478 : 10 : extractModify(DefElem *defel)
479 : : {
480 : 10 : char *val = defGetString(defel);
481 : :
482 [ - + ]: 10 : if (strcmp(val, "read_only") == 0)
2884 tgl@sss.pgh.pa.us 483 :UBC 0 : return AGGMODIFY_READ_ONLY;
2665 tgl@sss.pgh.pa.us 484 [ + + ]:CBC 10 : if (strcmp(val, "shareable") == 0)
485 : 7 : return AGGMODIFY_SHAREABLE;
2884 486 [ + - ]: 3 : if (strcmp(val, "read_write") == 0)
487 : 3 : return AGGMODIFY_READ_WRITE;
2884 tgl@sss.pgh.pa.us 488 [ # # ]:UBC 0 : ereport(ERROR,
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 : : }
|