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-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"
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
2718 rhodiumtoad@postgres 53 :CBC 585 : 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;
4630 tgl@sss.pgh.pa.us 63 : 585 : char aggKind = AGGKIND_NORMAL;
8900 64 : 585 : List *transfuncName = NIL;
65 : 585 : List *finalfuncName = NIL;
3872 rhaas@postgresql.org 66 : 585 : List *combinefuncName = NIL;
3803 67 : 585 : List *serialfuncName = NIL;
68 : 585 : List *deserialfuncName = NIL;
4520 tgl@sss.pgh.pa.us 69 : 585 : List *mtransfuncName = NIL;
70 : 585 : List *minvtransfuncName = NIL;
71 : 585 : List *mfinalfuncName = NIL;
4509 72 : 585 : bool finalfuncExtraArgs = false;
73 : 585 : bool mfinalfuncExtraArgs = false;
3239 74 : 585 : char finalfuncModify = 0;
75 : 585 : char mfinalfuncModify = 0;
7807 76 : 585 : List *sortoperatorName = NIL;
4 77 : 585 : List *supportfuncName = NIL;
8900 78 : 585 : TypeName *baseType = NULL;
79 : 585 : TypeName *transType = NULL;
4520 80 : 585 : TypeName *mtransType = NULL;
4667 81 : 585 : int32 transSpace = 0;
4520 82 : 585 : int32 mtransSpace = 0;
8900 83 : 585 : char *initval = NULL;
4520 84 : 585 : char *minitval = NULL;
3796 rhaas@postgresql.org 85 : 585 : char *parallel = NULL;
86 : : int numArgs;
4630 tgl@sss.pgh.pa.us 87 : 585 : int numDirectArgs = 0;
88 : : oidvector *parameterTypes;
89 : : ArrayType *allParameterTypes;
90 : : ArrayType *parameterModes;
91 : : ArrayType *parameterNames;
92 : : List *parameterDefaults;
93 : : Oid variadicArgType;
94 : : Oid transTypeId;
4520 95 : 585 : Oid mtransTypeId = InvalidOid;
96 : : char transTypeType;
97 : 585 : char mtransTypeType = 0;
3796 rhaas@postgresql.org 98 : 585 : char proparallel = PROPARALLEL_UNSAFE;
99 : : ListCell *pl;
100 : :
101 : : /* Convert list of names to a name and namespace */
7439 tgl@sss.pgh.pa.us 102 : 585 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
103 : :
104 : : /* Check we have creation rights in target namespace */
1383 peter@eisentraut.org 105 : 585 : aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
8888 tgl@sss.pgh.pa.us 106 [ - + ]: 585 : if (aclresult != ACLCHECK_OK)
3190 peter_e@gmx.net 107 :UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
8427 tgl@sss.pgh.pa.us 108 : 0 : get_namespace_name(aggNamespace));
109 : :
110 : : /* Deconstruct the output of the aggr_args grammar production */
4630 tgl@sss.pgh.pa.us 111 [ + + ]:CBC 585 : if (!oldstyle)
112 : : {
113 [ - + ]: 345 : Assert(list_length(args) == 2);
114 : 345 : numDirectArgs = intVal(lsecond(args));
115 [ + + ]: 345 : if (numDirectArgs >= 0)
116 : 14 : aggKind = AGGKIND_ORDERED_SET;
117 : : else
118 : 331 : numDirectArgs = 0;
3426 119 : 345 : args = linitial_node(List, args);
120 : : }
121 : :
122 : : /* Examine aggregate's definition clauses */
8900 123 [ + - + + : 2892 : foreach(pl, parameters)
+ + ]
124 : : {
3426 125 : 2307 : DefElem *defel = lfirst_node(DefElem, pl);
126 : :
127 : : /*
128 : : * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
129 : : * for sfunc, stype, initcond.
130 : : */
3135 131 [ + + ]: 2307 : if (strcmp(defel->defname, "sfunc") == 0)
8900 132 : 557 : transfuncName = defGetQualifiedName(defel);
3135 133 [ + + ]: 1750 : else if (strcmp(defel->defname, "sfunc1") == 0)
8900 134 : 20 : transfuncName = defGetQualifiedName(defel);
3135 135 [ + + ]: 1730 : else if (strcmp(defel->defname, "finalfunc") == 0)
8900 136 : 251 : finalfuncName = defGetQualifiedName(defel);
3135 137 [ + + ]: 1479 : else if (strcmp(defel->defname, "combinefunc") == 0)
3872 rhaas@postgresql.org 138 : 20 : combinefuncName = defGetQualifiedName(defel);
3135 tgl@sss.pgh.pa.us 139 [ + + ]: 1459 : else if (strcmp(defel->defname, "serialfunc") == 0)
3803 rhaas@postgresql.org 140 : 24 : serialfuncName = defGetQualifiedName(defel);
3135 tgl@sss.pgh.pa.us 141 [ + + ]: 1435 : else if (strcmp(defel->defname, "deserialfunc") == 0)
3803 rhaas@postgresql.org 142 : 20 : deserialfuncName = defGetQualifiedName(defel);
3135 tgl@sss.pgh.pa.us 143 [ + + ]: 1415 : else if (strcmp(defel->defname, "msfunc") == 0)
4520 144 : 38 : mtransfuncName = defGetQualifiedName(defel);
3135 145 [ + + ]: 1377 : else if (strcmp(defel->defname, "minvfunc") == 0)
4520 146 : 38 : minvtransfuncName = defGetQualifiedName(defel);
3135 147 [ - + ]: 1339 : else if (strcmp(defel->defname, "mfinalfunc") == 0)
4520 tgl@sss.pgh.pa.us 148 :UBC 0 : mfinalfuncName = defGetQualifiedName(defel);
3135 tgl@sss.pgh.pa.us 149 [ + + ]:CBC 1339 : else if (strcmp(defel->defname, "finalfunc_extra") == 0)
4509 150 : 10 : finalfuncExtraArgs = defGetBoolean(defel);
3135 151 [ - + ]: 1329 : else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
4509 tgl@sss.pgh.pa.us 152 :UBC 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
3135 tgl@sss.pgh.pa.us 153 [ + + ]:CBC 1329 : else if (strcmp(defel->defname, "finalfunc_modify") == 0)
3239 154 : 13 : finalfuncModify = extractModify(defel);
3135 155 [ - + ]: 1316 : else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
3239 tgl@sss.pgh.pa.us 156 :UBC 0 : mfinalfuncModify = extractModify(defel);
3135 tgl@sss.pgh.pa.us 157 [ + + ]:CBC 1316 : else if (strcmp(defel->defname, "sortop") == 0)
7807 158 : 4 : sortoperatorName = defGetQualifiedName(defel);
4 159 [ + + ]: 1312 : else if (strcmp(defel->defname, "support") == 0)
160 : 5 : supportfuncName = defGetQualifiedName(defel);
3135 161 [ + + ]: 1307 : else if (strcmp(defel->defname, "basetype") == 0)
8900 162 : 232 : baseType = defGetTypeName(defel);
3135 163 [ + + ]: 1075 : else if (strcmp(defel->defname, "hypothetical") == 0)
164 : : {
4630 165 [ + - ]: 5 : if (defGetBoolean(defel))
166 : : {
167 [ - + ]: 5 : if (aggKind == AGGKIND_NORMAL)
4630 tgl@sss.pgh.pa.us 168 [ # # ]:UBC 0 : ereport(ERROR,
169 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
170 : : errmsg("only ordered-set aggregates can be hypothetical")));
4630 tgl@sss.pgh.pa.us 171 :CBC 5 : aggKind = AGGKIND_HYPOTHETICAL;
172 : : }
173 : : }
3135 174 [ + + ]: 1070 : else if (strcmp(defel->defname, "stype") == 0)
8900 175 : 557 : transType = defGetTypeName(defel);
3135 176 [ + + ]: 513 : else if (strcmp(defel->defname, "stype1") == 0)
8900 177 : 20 : transType = defGetTypeName(defel);
3135 178 [ + + ]: 493 : else if (strcmp(defel->defname, "sspace") == 0)
4667 179 : 5 : transSpace = defGetInt32(defel);
3135 180 [ + + ]: 488 : else if (strcmp(defel->defname, "mstype") == 0)
4520 181 : 38 : mtransType = defGetTypeName(defel);
3135 182 [ - + ]: 450 : else if (strcmp(defel->defname, "msspace") == 0)
4520 tgl@sss.pgh.pa.us 183 :UBC 0 : mtransSpace = defGetInt32(defel);
3135 tgl@sss.pgh.pa.us 184 [ + + ]:CBC 450 : else if (strcmp(defel->defname, "initcond") == 0)
8900 185 : 364 : initval = defGetString(defel);
3135 186 [ + + ]: 86 : else if (strcmp(defel->defname, "initcond1") == 0)
8900 187 : 11 : initval = defGetString(defel);
3135 188 [ + + ]: 75 : else if (strcmp(defel->defname, "minitcond") == 0)
4520 189 : 10 : minitval = defGetString(defel);
3135 190 [ + + ]: 65 : else if (strcmp(defel->defname, "parallel") == 0)
3796 rhaas@postgresql.org 191 : 21 : parallel = defGetString(defel);
192 : : else
8439 tgl@sss.pgh.pa.us 193 [ + - ]: 44 : ereport(WARNING,
194 : : (errcode(ERRCODE_SYNTAX_ERROR),
195 : : errmsg("aggregate attribute \"%s\" not recognized",
196 : : defel->defname)));
197 : : }
198 : :
199 : : /*
200 : : * make sure we have our required definitions
201 : : */
8900 202 [ + + ]: 585 : if (transType == NULL)
8439 203 [ + - ]: 8 : ereport(ERROR,
204 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
205 : : errmsg("aggregate stype must be specified")));
8900 206 [ - + ]: 577 : if (transfuncName == NIL)
8439 tgl@sss.pgh.pa.us 207 [ # # ]:UBC 0 : ereport(ERROR,
208 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
209 : : errmsg("aggregate sfunc must be specified")));
210 : :
211 : : /*
212 : : * if mtransType is given, mtransfuncName and minvtransfuncName must be as
213 : : * well; if not, then none of the moving-aggregate options should have
214 : : * been given.
215 : : */
4520 tgl@sss.pgh.pa.us 216 [ + + ]:CBC 577 : if (mtransType != NULL)
217 : : {
218 [ - + ]: 38 : if (mtransfuncName == NIL)
4520 tgl@sss.pgh.pa.us 219 [ # # ]:UBC 0 : ereport(ERROR,
220 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
221 : : errmsg("aggregate msfunc must be specified when mstype is specified")));
4520 tgl@sss.pgh.pa.us 222 [ - + ]:CBC 38 : if (minvtransfuncName == NIL)
4520 tgl@sss.pgh.pa.us 223 [ # # ]:UBC 0 : ereport(ERROR,
224 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
225 : : errmsg("aggregate minvfunc must be specified when mstype is specified")));
226 : : }
227 : : else
228 : : {
4520 tgl@sss.pgh.pa.us 229 [ - + ]:CBC 539 : if (mtransfuncName != NIL)
4520 tgl@sss.pgh.pa.us 230 [ # # ]:UBC 0 : ereport(ERROR,
231 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
232 : : errmsg("aggregate msfunc must not be specified without mstype")));
4520 tgl@sss.pgh.pa.us 233 [ - + ]:CBC 539 : if (minvtransfuncName != NIL)
4520 tgl@sss.pgh.pa.us 234 [ # # ]:UBC 0 : ereport(ERROR,
235 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
236 : : errmsg("aggregate minvfunc must not be specified without mstype")));
4520 tgl@sss.pgh.pa.us 237 [ - + ]:CBC 539 : if (mfinalfuncName != NIL)
4520 tgl@sss.pgh.pa.us 238 [ # # ]:UBC 0 : ereport(ERROR,
239 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
240 : : errmsg("aggregate mfinalfunc must not be specified without mstype")));
4520 tgl@sss.pgh.pa.us 241 [ - + ]:CBC 539 : if (mtransSpace != 0)
4520 tgl@sss.pgh.pa.us 242 [ # # ]:UBC 0 : ereport(ERROR,
243 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
244 : : errmsg("aggregate msspace must not be specified without mstype")));
4520 tgl@sss.pgh.pa.us 245 [ - + ]:CBC 539 : if (minitval != NULL)
4520 tgl@sss.pgh.pa.us 246 [ # # ]:UBC 0 : ereport(ERROR,
247 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
248 : : errmsg("aggregate minitcond must not be specified without mstype")));
249 : : }
250 : :
251 : : /*
252 : : * Default values for modify flags can only be determined once we know the
253 : : * aggKind.
254 : : */
3239 tgl@sss.pgh.pa.us 255 [ + + ]:CBC 577 : if (finalfuncModify == 0)
256 [ + + ]: 564 : finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
257 [ + - ]: 577 : if (mfinalfuncModify == 0)
258 [ + + ]: 577 : mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
259 : :
260 : : /*
261 : : * look up the aggregate's input datatype(s).
262 : : */
7439 263 [ + + ]: 577 : if (oldstyle)
264 : : {
265 : : /*
266 : : * Old style: use basetype parameter. This supports aggregates of
267 : : * zero or one input, with input type ANY meaning zero inputs.
268 : : *
269 : : * Historically we allowed the command to look like basetype = 'ANY'
270 : : * so we must do a case-insensitive comparison for the name ANY. Ugh.
271 : : */
272 : : Oid aggArgTypes[1];
273 : :
274 [ + + ]: 236 : if (baseType == NULL)
275 [ + - ]: 4 : ereport(ERROR,
276 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
277 : : errmsg("aggregate input type must be specified")));
278 : :
279 [ + + ]: 232 : if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
280 : : {
7336 281 : 4 : numArgs = 0;
4741 282 : 4 : aggArgTypes[0] = InvalidOid;
283 : : }
284 : : else
285 : : {
7336 286 : 228 : numArgs = 1;
5785 peter_e@gmx.net 287 : 228 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
288 : : }
4741 tgl@sss.pgh.pa.us 289 : 232 : parameterTypes = buildoidvector(aggArgTypes, numArgs);
290 : 232 : allParameterTypes = NULL;
291 : 232 : parameterModes = NULL;
292 : 232 : parameterNames = NULL;
293 : 232 : parameterDefaults = NIL;
4630 294 : 232 : variadicArgType = InvalidOid;
295 : : }
296 : : else
297 : : {
298 : : /*
299 : : * New style: args is a list of FunctionParameters (possibly zero of
300 : : * 'em). We share functioncmds.c's code for processing them.
301 : : */
302 : : Oid requiredResultType;
303 : :
7439 304 [ - + ]: 341 : if (baseType != NULL)
7439 tgl@sss.pgh.pa.us 305 [ # # ]:UBC 0 : ereport(ERROR,
306 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
307 : : errmsg("basetype is redundant with aggregate input type specification")));
308 : :
7336 tgl@sss.pgh.pa.us 309 :CBC 341 : numArgs = list_length(args);
3642 peter_e@gmx.net 310 : 341 : interpret_function_parameter_list(pstate,
311 : : args,
312 : : InvalidOid,
313 : : OBJECT_AGGREGATE,
314 : : ¶meterTypes,
315 : : NULL,
316 : : &allParameterTypes,
317 : : ¶meterModes,
318 : : ¶meterNames,
319 : : NULL,
320 : : ¶meterDefaults,
321 : : &variadicArgType,
322 : : &requiredResultType);
323 : : /* Parameter defaults are not currently allowed by the grammar */
4741 tgl@sss.pgh.pa.us 324 [ - + ]: 337 : Assert(parameterDefaults == NIL);
325 : : /* There shouldn't have been any OUT parameters, either */
326 [ - + ]: 337 : Assert(requiredResultType == InvalidOid);
327 : : }
328 : :
329 : : /*
330 : : * look up the aggregate's transtype.
331 : : *
332 : : * transtype can't be a pseudo-type, since we need to be able to store
333 : : * values of the transtype. However, we can allow polymorphic transtype
334 : : * in some cases (AggregateCreate will check). Also, we allow "internal"
335 : : * for functions that want to pass pointers to private data structures;
336 : : * but allow that only to superusers, since you could crash the system (or
337 : : * worse) by connecting up incompatible internal-using functions in an
338 : : * aggregate.
339 : : */
5785 peter_e@gmx.net 340 : 569 : transTypeId = typenameTypeId(NULL, transType);
5075 tgl@sss.pgh.pa.us 341 : 569 : transTypeType = get_typtype(transTypeId);
342 [ + + + + ]: 569 : if (transTypeType == TYPTYPE_PSEUDO &&
7087 343 [ + + + - : 184 : !IsPolymorphicType(transTypeId))
+ - + - +
- + + + -
+ - + - +
- ]
344 : : {
6495 345 [ + - + - ]: 38 : if (transTypeId == INTERNALOID && superuser())
346 : : /* okay */ ;
347 : : else
6495 tgl@sss.pgh.pa.us 348 [ # # ]:UBC 0 : ereport(ERROR,
349 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
350 : : errmsg("aggregate transition data type cannot be %s",
351 : : format_type_be(transTypeId))));
352 : : }
353 : :
3718 tgl@sss.pgh.pa.us 354 [ + + + + ]:CBC 569 : if (serialfuncName && deserialfuncName)
355 : : {
356 : : /*
357 : : * Serialization is only needed/allowed for transtype INTERNAL.
358 : : */
3803 rhaas@postgresql.org 359 [ - + ]: 20 : if (transTypeId != INTERNALOID)
3803 rhaas@postgresql.org 360 [ # # ]:UBC 0 : ereport(ERROR,
361 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
362 : : errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
363 : : format_type_be(INTERNALOID))));
364 : : }
3718 tgl@sss.pgh.pa.us 365 [ + + - + ]:CBC 549 : else if (serialfuncName || deserialfuncName)
366 : : {
367 : : /*
368 : : * Cannot specify one function without the other.
369 : : */
370 [ + - ]: 4 : ereport(ERROR,
371 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
372 : : errmsg("must specify both or neither of serialization and deserialization functions")));
373 : : }
374 : :
375 : : /*
376 : : * If a moving-aggregate transtype is specified, look that up. Same
377 : : * restrictions as for transtype.
378 : : */
4520 379 [ + + ]: 565 : if (mtransType)
380 : : {
381 : 38 : mtransTypeId = typenameTypeId(NULL, mtransType);
382 : 38 : mtransTypeType = get_typtype(mtransTypeId);
383 [ - + - - ]: 38 : if (mtransTypeType == TYPTYPE_PSEUDO &&
4520 tgl@sss.pgh.pa.us 384 [ # # # # :UBC 0 : !IsPolymorphicType(mtransTypeId))
# # # # #
# # # # #
# # # # #
# ]
385 : : {
386 [ # # # # ]: 0 : if (mtransTypeId == INTERNALOID && superuser())
387 : : /* okay */ ;
388 : : else
389 [ # # ]: 0 : ereport(ERROR,
390 : : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
391 : : errmsg("aggregate transition data type cannot be %s",
392 : : format_type_be(mtransTypeId))));
393 : : }
394 : : }
395 : :
396 : : /*
397 : : * If we have an initval, and it's not for a pseudotype (particularly a
398 : : * polymorphic type), make sure it's acceptable to the type's input
399 : : * function. We will store the initval as text, because the input
400 : : * function isn't necessarily immutable (consider "now" for timestamp),
401 : : * and we want to use the runtime not creation-time interpretation of the
402 : : * value. However, if it's an incorrect value it seems much more
403 : : * user-friendly to complain at CREATE AGGREGATE time.
404 : : */
5075 tgl@sss.pgh.pa.us 405 [ + + + + ]:CBC 565 : if (initval && transTypeType != TYPTYPE_PSEUDO)
406 : : {
407 : : Oid typinput,
408 : : typioparam;
409 : :
410 : 239 : getTypeInputInfo(transTypeId, &typinput, &typioparam);
411 : 239 : (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
412 : : }
413 : :
414 : : /*
415 : : * Likewise for moving-aggregate initval.
416 : : */
4520 417 [ + + + - ]: 565 : if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
418 : : {
419 : : Oid typinput,
420 : : typioparam;
421 : :
422 : 10 : getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
423 : 10 : (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
424 : : }
425 : :
3796 rhaas@postgresql.org 426 [ + + ]: 565 : if (parallel)
427 : : {
3135 tgl@sss.pgh.pa.us 428 [ + + ]: 21 : if (strcmp(parallel, "safe") == 0)
3796 rhaas@postgresql.org 429 : 17 : proparallel = PROPARALLEL_SAFE;
3135 tgl@sss.pgh.pa.us 430 [ - + ]: 4 : else if (strcmp(parallel, "restricted") == 0)
3796 rhaas@postgresql.org 431 :UBC 0 : proparallel = PROPARALLEL_RESTRICTED;
3135 tgl@sss.pgh.pa.us 432 [ - + ]:CBC 4 : else if (strcmp(parallel, "unsafe") == 0)
3796 rhaas@postgresql.org 433 :UBC 0 : proparallel = PROPARALLEL_UNSAFE;
434 : : else
3796 rhaas@postgresql.org 435 [ + - ]:CBC 4 : ereport(ERROR,
436 : : (errcode(ERRCODE_SYNTAX_ERROR),
437 : : errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
438 : : }
439 : :
440 : : /*
441 : : * Most of the argument-checking is done inside of AggregateCreate
442 : : */
3354 tgl@sss.pgh.pa.us 443 : 561 : return AggregateCreate(aggName, /* aggregate name */
444 : : aggNamespace, /* namespace */
445 : : replace,
446 : : aggKind,
447 : : numArgs,
448 : : numDirectArgs,
449 : : parameterTypes,
450 : : PointerGetDatum(allParameterTypes),
451 : : PointerGetDatum(parameterModes),
452 : : PointerGetDatum(parameterNames),
453 : : parameterDefaults,
454 : : variadicArgType,
455 : : transfuncName, /* step function name */
456 : : finalfuncName, /* final function name */
457 : : combinefuncName, /* combine function name */
458 : : serialfuncName, /* serial function name */
459 : : deserialfuncName, /* deserial function name */
460 : : mtransfuncName, /* fwd trans function name */
461 : : minvtransfuncName, /* inv trans function name */
462 : : mfinalfuncName, /* final function name */
463 : : finalfuncExtraArgs,
464 : : mfinalfuncExtraArgs,
465 : : finalfuncModify,
466 : : mfinalfuncModify,
467 : : sortoperatorName, /* sort operator name */
468 : : supportfuncName, /* planner support func 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
3239 482 : 13 : extractModify(DefElem *defel)
483 : : {
484 : 13 : char *val = defGetString(defel);
485 : :
486 [ - + ]: 13 : if (strcmp(val, "read_only") == 0)
3239 tgl@sss.pgh.pa.us 487 :UBC 0 : return AGGMODIFY_READ_ONLY;
3020 tgl@sss.pgh.pa.us 488 [ + + ]:CBC 13 : if (strcmp(val, "shareable") == 0)
489 : 9 : return AGGMODIFY_SHAREABLE;
3239 490 [ + - ]: 4 : if (strcmp(val, "read_write") == 0)
491 : 4 : return AGGMODIFY_READ_WRITE;
3239 tgl@sss.pgh.pa.us 492 [ # # ]:UBC 0 : ereport(ERROR,
493 : : (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 : : }
|