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-2024, 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 "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
1853 rhodiumtoad@postgres 53 :CBC 452 : 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;
3765 tgl@sss.pgh.pa.us 63 : 452 : char aggKind = AGGKIND_NORMAL;
8035 64 : 452 : List *transfuncName = NIL;
65 : 452 : List *finalfuncName = NIL;
3007 rhaas@postgresql.org 66 : 452 : List *combinefuncName = NIL;
2938 67 : 452 : List *serialfuncName = NIL;
68 : 452 : List *deserialfuncName = NIL;
3655 tgl@sss.pgh.pa.us 69 : 452 : List *mtransfuncName = NIL;
70 : 452 : List *minvtransfuncName = NIL;
71 : 452 : List *mfinalfuncName = NIL;
3644 72 : 452 : bool finalfuncExtraArgs = false;
73 : 452 : bool mfinalfuncExtraArgs = false;
2374 74 : 452 : char finalfuncModify = 0;
75 : 452 : char mfinalfuncModify = 0;
6942 76 : 452 : List *sortoperatorName = NIL;
8035 77 : 452 : TypeName *baseType = NULL;
78 : 452 : TypeName *transType = NULL;
3655 79 : 452 : TypeName *mtransType = NULL;
3802 80 : 452 : int32 transSpace = 0;
3655 81 : 452 : int32 mtransSpace = 0;
8035 82 : 452 : char *initval = NULL;
3655 83 : 452 : char *minitval = NULL;
2931 rhaas@postgresql.org 84 : 452 : char *parallel = NULL;
85 : : int numArgs;
3765 tgl@sss.pgh.pa.us 86 : 452 : int numDirectArgs = 0;
87 : : oidvector *parameterTypes;
88 : : ArrayType *allParameterTypes;
89 : : ArrayType *parameterModes;
90 : : ArrayType *parameterNames;
91 : : List *parameterDefaults;
92 : : Oid variadicArgType;
93 : : Oid transTypeId;
3655 94 : 452 : Oid mtransTypeId = InvalidOid;
95 : : char transTypeType;
96 : 452 : char mtransTypeType = 0;
2931 rhaas@postgresql.org 97 : 452 : char proparallel = PROPARALLEL_UNSAFE;
98 : : ListCell *pl;
99 : :
100 : : /* Convert list of names to a name and namespace */
6574 tgl@sss.pgh.pa.us 101 : 452 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
102 : :
103 : : /* Check we have creation rights in target namespace */
518 peter@eisentraut.org 104 : 452 : aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
8023 tgl@sss.pgh.pa.us 105 [ - + ]: 452 : if (aclresult != ACLCHECK_OK)
2325 peter_e@gmx.net 106 :UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7562 tgl@sss.pgh.pa.us 107 : 0 : get_namespace_name(aggNamespace));
108 : :
109 : : /* Deconstruct the output of the aggr_args grammar production */
3765 tgl@sss.pgh.pa.us 110 [ + + ]:CBC 452 : if (!oldstyle)
111 : : {
112 [ - + ]: 271 : Assert(list_length(args) == 2);
113 : 271 : numDirectArgs = intVal(lsecond(args));
114 [ + + ]: 271 : if (numDirectArgs >= 0)
115 : 11 : aggKind = AGGKIND_ORDERED_SET;
116 : : else
117 : 260 : numDirectArgs = 0;
2561 118 : 271 : args = linitial_node(List, args);
119 : : }
120 : :
121 : : /* Examine aggregate's definition clauses */
8035 122 [ + - + + : 2228 : foreach(pl, parameters)
+ + ]
123 : : {
2561 124 : 1776 : DefElem *defel = lfirst_node(DefElem, pl);
125 : :
126 : : /*
127 : : * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
128 : : * for sfunc, stype, initcond.
129 : : */
2270 130 [ + + ]: 1776 : if (strcmp(defel->defname, "sfunc") == 0)
8035 131 : 431 : transfuncName = defGetQualifiedName(defel);
2270 132 [ + + ]: 1345 : else if (strcmp(defel->defname, "sfunc1") == 0)
8035 133 : 15 : transfuncName = defGetQualifiedName(defel);
2270 134 [ + + ]: 1330 : else if (strcmp(defel->defname, "finalfunc") == 0)
8035 135 : 194 : finalfuncName = defGetQualifiedName(defel);
2270 136 [ + + ]: 1136 : else if (strcmp(defel->defname, "combinefunc") == 0)
3007 rhaas@postgresql.org 137 : 16 : combinefuncName = defGetQualifiedName(defel);
2270 tgl@sss.pgh.pa.us 138 [ + + ]: 1120 : else if (strcmp(defel->defname, "serialfunc") == 0)
2938 rhaas@postgresql.org 139 : 18 : serialfuncName = defGetQualifiedName(defel);
2270 tgl@sss.pgh.pa.us 140 [ + + ]: 1102 : else if (strcmp(defel->defname, "deserialfunc") == 0)
2938 rhaas@postgresql.org 141 : 15 : deserialfuncName = defGetQualifiedName(defel);
2270 tgl@sss.pgh.pa.us 142 [ + + ]: 1087 : else if (strcmp(defel->defname, "msfunc") == 0)
3655 143 : 30 : mtransfuncName = defGetQualifiedName(defel);
2270 144 [ + + ]: 1057 : else if (strcmp(defel->defname, "minvfunc") == 0)
3655 145 : 30 : minvtransfuncName = defGetQualifiedName(defel);
2270 146 [ - + ]: 1027 : else if (strcmp(defel->defname, "mfinalfunc") == 0)
3655 tgl@sss.pgh.pa.us 147 :UBC 0 : mfinalfuncName = defGetQualifiedName(defel);
2270 tgl@sss.pgh.pa.us 148 [ + + ]:CBC 1027 : else if (strcmp(defel->defname, "finalfunc_extra") == 0)
3644 149 : 8 : finalfuncExtraArgs = defGetBoolean(defel);
2270 150 [ - + ]: 1019 : else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
3644 tgl@sss.pgh.pa.us 151 :UBC 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
2270 tgl@sss.pgh.pa.us 152 [ + + ]:CBC 1019 : else if (strcmp(defel->defname, "finalfunc_modify") == 0)
2374 153 : 10 : finalfuncModify = extractModify(defel);
2270 154 [ - + ]: 1009 : else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
2374 tgl@sss.pgh.pa.us 155 :UBC 0 : mfinalfuncModify = extractModify(defel);
2270 tgl@sss.pgh.pa.us 156 [ + + ]:CBC 1009 : else if (strcmp(defel->defname, "sortop") == 0)
6942 157 : 4 : sortoperatorName = defGetQualifiedName(defel);
2270 158 [ + + ]: 1005 : else if (strcmp(defel->defname, "basetype") == 0)
8035 159 : 175 : baseType = defGetTypeName(defel);
2270 160 [ + + ]: 830 : else if (strcmp(defel->defname, "hypothetical") == 0)
161 : : {
3765 162 [ + - ]: 4 : if (defGetBoolean(defel))
163 : : {
164 [ - + ]: 4 : if (aggKind == AGGKIND_NORMAL)
3765 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")));
3765 tgl@sss.pgh.pa.us 168 :CBC 4 : aggKind = AGGKIND_HYPOTHETICAL;
169 : : }
170 : : }
2270 171 [ + + ]: 826 : else if (strcmp(defel->defname, "stype") == 0)
8035 172 : 431 : transType = defGetTypeName(defel);
2270 173 [ + + ]: 395 : else if (strcmp(defel->defname, "stype1") == 0)
8035 174 : 15 : transType = defGetTypeName(defel);
2270 175 [ + + ]: 380 : else if (strcmp(defel->defname, "sspace") == 0)
3802 176 : 4 : transSpace = defGetInt32(defel);
2270 177 [ + + ]: 376 : else if (strcmp(defel->defname, "mstype") == 0)
3655 178 : 30 : mtransType = defGetTypeName(defel);
2270 179 [ - + ]: 346 : else if (strcmp(defel->defname, "msspace") == 0)
3655 tgl@sss.pgh.pa.us 180 :UBC 0 : mtransSpace = defGetInt32(defel);
2270 tgl@sss.pgh.pa.us 181 [ + + ]:CBC 346 : else if (strcmp(defel->defname, "initcond") == 0)
8035 182 : 279 : initval = defGetString(defel);
2270 183 [ + + ]: 67 : else if (strcmp(defel->defname, "initcond1") == 0)
8035 184 : 9 : initval = defGetString(defel);
2270 185 [ + + ]: 58 : else if (strcmp(defel->defname, "minitcond") == 0)
3655 186 : 8 : minitval = defGetString(defel);
2270 187 [ + + ]: 50 : else if (strcmp(defel->defname, "parallel") == 0)
2931 rhaas@postgresql.org 188 : 17 : parallel = defGetString(defel);
189 : : else
7574 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 : : */
8035 199 [ + + ]: 452 : if (transType == NULL)
7574 200 [ + - ]: 6 : ereport(ERROR,
201 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
202 : : errmsg("aggregate stype must be specified")));
8035 203 [ - + ]: 446 : if (transfuncName == NIL)
7574 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 : : */
3655 tgl@sss.pgh.pa.us 213 [ + + ]:CBC 446 : if (mtransType != NULL)
214 : : {
215 [ - + ]: 30 : if (mtransfuncName == NIL)
3655 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")));
3655 tgl@sss.pgh.pa.us 219 [ - + ]:CBC 30 : if (minvtransfuncName == NIL)
3655 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 : : {
3655 tgl@sss.pgh.pa.us 226 [ - + ]:CBC 416 : if (mtransfuncName != NIL)
3655 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")));
3655 tgl@sss.pgh.pa.us 230 [ - + ]:CBC 416 : if (minvtransfuncName != NIL)
3655 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")));
3655 tgl@sss.pgh.pa.us 234 [ - + ]:CBC 416 : if (mfinalfuncName != NIL)
3655 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")));
3655 tgl@sss.pgh.pa.us 238 [ - + ]:CBC 416 : if (mtransSpace != 0)
3655 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")));
3655 tgl@sss.pgh.pa.us 242 [ - + ]:CBC 416 : if (minitval != NULL)
3655 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 : : */
2374 tgl@sss.pgh.pa.us 252 [ + + ]:CBC 446 : if (finalfuncModify == 0)
253 [ + + ]: 436 : finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
254 [ + - ]: 446 : if (mfinalfuncModify == 0)
255 [ + + ]: 446 : mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
256 : :
257 : : /*
258 : : * look up the aggregate's input datatype(s).
259 : : */
6574 260 [ + + ]: 446 : 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 : : {
6471 278 : 3 : numArgs = 0;
3876 279 : 3 : aggArgTypes[0] = InvalidOid;
280 : : }
281 : : else
282 : : {
6471 283 : 172 : numArgs = 1;
4920 peter_e@gmx.net 284 : 172 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
285 : : }
3876 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;
3765 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 : :
6574 301 [ - + ]: 268 : if (baseType != NULL)
6574 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 : :
6471 tgl@sss.pgh.pa.us 306 :CBC 268 : numArgs = list_length(args);
2777 peter_e@gmx.net 307 : 268 : 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 */
3876 tgl@sss.pgh.pa.us 321 [ - + ]: 265 : Assert(parameterDefaults == NIL);
322 : : /* There shouldn't have been any OUT parameters, either */
323 [ - + ]: 265 : 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 : : */
4920 peter_e@gmx.net 337 : 440 : transTypeId = typenameTypeId(NULL, transType);
4210 tgl@sss.pgh.pa.us 338 : 440 : transTypeType = get_typtype(transTypeId);
339 [ + + + + ]: 440 : if (transTypeType == TYPTYPE_PSEUDO &&
6222 340 [ + + + - : 140 : !IsPolymorphicType(transTypeId))
+ - + - +
- + + + -
+ - + - +
- ]
341 : : {
5630 342 [ + - + - ]: 29 : if (transTypeId == INTERNALOID && superuser())
343 : : /* okay */ ;
344 : : else
5630 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 : :
2853 tgl@sss.pgh.pa.us 351 [ + + + + ]:CBC 440 : if (serialfuncName && deserialfuncName)
352 : : {
353 : : /*
354 : : * Serialization is only needed/allowed for transtype INTERNAL.
355 : : */
2938 rhaas@postgresql.org 356 [ - + ]: 15 : if (transTypeId != INTERNALOID)
2938 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 : : }
2853 tgl@sss.pgh.pa.us 362 [ + + - + ]:CBC 425 : 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 : : */
3655 376 [ + + ]: 437 : if (mtransType)
377 : : {
378 : 30 : mtransTypeId = typenameTypeId(NULL, mtransType);
379 : 30 : mtransTypeType = get_typtype(mtransTypeId);
380 [ - + - - ]: 30 : if (mtransTypeType == TYPTYPE_PSEUDO &&
3655 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 : : */
4210 tgl@sss.pgh.pa.us 402 [ + + + + ]:CBC 437 : 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 : : */
3655 414 [ + + + - ]: 437 : 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 : :
2931 rhaas@postgresql.org 423 [ + + ]: 437 : if (parallel)
424 : : {
2270 tgl@sss.pgh.pa.us 425 [ + + ]: 17 : if (strcmp(parallel, "safe") == 0)
2931 rhaas@postgresql.org 426 : 14 : proparallel = PROPARALLEL_SAFE;
2270 tgl@sss.pgh.pa.us 427 [ - + ]: 3 : else if (strcmp(parallel, "restricted") == 0)
2931 rhaas@postgresql.org 428 :UBC 0 : proparallel = PROPARALLEL_RESTRICTED;
2270 tgl@sss.pgh.pa.us 429 [ - + ]:CBC 3 : else if (strcmp(parallel, "unsafe") == 0)
2931 rhaas@postgresql.org 430 :UBC 0 : proparallel = PROPARALLEL_UNSAFE;
431 : : else
2931 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 : : */
2489 tgl@sss.pgh.pa.us 440 : 434 : 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
2374 478 : 10 : extractModify(DefElem *defel)
479 : : {
480 : 10 : char *val = defGetString(defel);
481 : :
482 [ - + ]: 10 : if (strcmp(val, "read_only") == 0)
2374 tgl@sss.pgh.pa.us 483 :UBC 0 : return AGGMODIFY_READ_ONLY;
2155 tgl@sss.pgh.pa.us 484 [ + + ]:CBC 10 : if (strcmp(val, "shareable") == 0)
485 : 7 : return AGGMODIFY_SHAREABLE;
2374 486 [ + - ]: 3 : if (strcmp(val, "read_write") == 0)
487 : 3 : return AGGMODIFY_READ_WRITE;
2374 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 : : }
|