Age Owner 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
1482 rhodiumtoad 57 GIC 449 : DefineAggregate(ParseState *pstate,
1482 rhodiumtoad 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;
3394 tgl 67 GIC 449 : char aggKind = AGGKIND_NORMAL;
7664 tgl 68 CBC 449 : List *transfuncName = NIL;
69 449 : List *finalfuncName = NIL;
2636 rhaas 70 449 : List *combinefuncName = NIL;
2567 71 449 : List *serialfuncName = NIL;
72 449 : List *deserialfuncName = NIL;
3284 tgl 73 449 : List *mtransfuncName = NIL;
74 449 : List *minvtransfuncName = NIL;
75 449 : List *mfinalfuncName = NIL;
3273 76 449 : bool finalfuncExtraArgs = false;
77 449 : bool mfinalfuncExtraArgs = false;
2003 78 449 : char finalfuncModify = 0;
79 449 : char mfinalfuncModify = 0;
6571 80 449 : List *sortoperatorName = NIL;
7664 81 449 : TypeName *baseType = NULL;
82 449 : TypeName *transType = NULL;
3284 83 449 : TypeName *mtransType = NULL;
3431 84 449 : int32 transSpace = 0;
3284 85 449 : int32 mtransSpace = 0;
7664 86 449 : char *initval = NULL;
3284 87 449 : char *minitval = NULL;
2560 rhaas 88 449 : char *parallel = NULL;
6031 bruce 89 ECB : int numArgs;
3394 tgl 90 GIC 449 : int numDirectArgs = 0;
3505 tgl 91 ECB : oidvector *parameterTypes;
92 : ArrayType *allParameterTypes;
93 : ArrayType *parameterModes;
94 : ArrayType *parameterNames;
95 : List *parameterDefaults;
96 : Oid variadicArgType;
97 : Oid transTypeId;
3284 tgl 98 GIC 449 : Oid mtransTypeId = InvalidOid;
3839 tgl 99 ECB : char transTypeType;
3284 tgl 100 GIC 449 : char mtransTypeType = 0;
2560 rhaas 101 CBC 449 : char proparallel = PROPARALLEL_UNSAFE;
6892 neilc 102 ECB : ListCell *pl;
103 :
104 : /* Convert list of names to a name and namespace */
6203 tgl 105 GIC 449 : aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
7664 tgl 106 ECB :
107 : /* Check we have creation rights in target namespace */
147 peter 108 GNC 449 : aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
7652 tgl 109 CBC 449 : if (aclresult != ACLCHECK_OK)
1954 peter_e 110 LBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7191 tgl 111 UBC 0 : get_namespace_name(aggNamespace));
7652 tgl 112 EUB :
113 : /* Deconstruct the output of the aggr_args grammar production */
3394 tgl 114 GIC 449 : if (!oldstyle)
3394 tgl 115 ECB : {
3394 tgl 116 GIC 268 : Assert(list_length(args) == 2);
3394 tgl 117 CBC 268 : numDirectArgs = intVal(lsecond(args));
118 268 : if (numDirectArgs >= 0)
119 11 : aggKind = AGGKIND_ORDERED_SET;
3394 tgl 120 ECB : else
3394 tgl 121 GIC 257 : numDirectArgs = 0;
2190 tgl 122 CBC 268 : args = linitial_node(List, args);
3394 tgl 123 ECB : }
124 :
125 : /* Examine aggregate's definition clauses */
7664 tgl 126 GIC 2216 : foreach(pl, parameters)
7664 tgl 127 ECB : {
2190 tgl 128 GIC 1767 : DefElem *defel = lfirst_node(DefElem, pl);
7664 tgl 129 ECB :
130 : /*
131 : * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
132 : * for sfunc, stype, initcond.
133 : */
1899 tgl 134 GIC 1767 : if (strcmp(defel->defname, "sfunc") == 0)
7664 tgl 135 CBC 428 : transfuncName = defGetQualifiedName(defel);
1899 136 1339 : else if (strcmp(defel->defname, "sfunc1") == 0)
7664 137 15 : transfuncName = defGetQualifiedName(defel);
1899 138 1324 : else if (strcmp(defel->defname, "finalfunc") == 0)
7664 139 191 : finalfuncName = defGetQualifiedName(defel);
1899 140 1133 : else if (strcmp(defel->defname, "combinefunc") == 0)
2636 rhaas 141 16 : combinefuncName = defGetQualifiedName(defel);
1899 tgl 142 1117 : else if (strcmp(defel->defname, "serialfunc") == 0)
2567 rhaas 143 18 : serialfuncName = defGetQualifiedName(defel);
1899 tgl 144 1099 : else if (strcmp(defel->defname, "deserialfunc") == 0)
2567 rhaas 145 15 : deserialfuncName = defGetQualifiedName(defel);
1899 tgl 146 1084 : else if (strcmp(defel->defname, "msfunc") == 0)
3284 147 30 : mtransfuncName = defGetQualifiedName(defel);
1899 148 1054 : else if (strcmp(defel->defname, "minvfunc") == 0)
3284 149 30 : minvtransfuncName = defGetQualifiedName(defel);
1899 150 1024 : else if (strcmp(defel->defname, "mfinalfunc") == 0)
3284 tgl 151 LBC 0 : mfinalfuncName = defGetQualifiedName(defel);
1899 tgl 152 GBC 1024 : else if (strcmp(defel->defname, "finalfunc_extra") == 0)
3273 tgl 153 CBC 8 : finalfuncExtraArgs = defGetBoolean(defel);
1899 154 1016 : else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
3273 tgl 155 LBC 0 : mfinalfuncExtraArgs = defGetBoolean(defel);
1899 tgl 156 GBC 1016 : else if (strcmp(defel->defname, "finalfunc_modify") == 0)
2003 tgl 157 CBC 10 : finalfuncModify = extractModify(defel);
1899 158 1006 : else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
2003 tgl 159 LBC 0 : mfinalfuncModify = extractModify(defel);
1899 tgl 160 GBC 1006 : else if (strcmp(defel->defname, "sortop") == 0)
6571 tgl 161 CBC 4 : sortoperatorName = defGetQualifiedName(defel);
1899 162 1002 : else if (strcmp(defel->defname, "basetype") == 0)
7664 163 175 : baseType = defGetTypeName(defel);
1899 164 827 : else if (strcmp(defel->defname, "hypothetical") == 0)
3394 tgl 165 ECB : {
3394 tgl 166 GIC 4 : if (defGetBoolean(defel))
3394 tgl 167 ECB : {
3394 tgl 168 GIC 4 : if (aggKind == AGGKIND_NORMAL)
3394 tgl 169 LBC 0 : ereport(ERROR,
3394 tgl 170 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
171 : errmsg("only ordered-set aggregates can be hypothetical")));
3394 tgl 172 GIC 4 : aggKind = AGGKIND_HYPOTHETICAL;
3394 tgl 173 ECB : }
174 : }
1899 tgl 175 GIC 823 : else if (strcmp(defel->defname, "stype") == 0)
7664 tgl 176 CBC 428 : transType = defGetTypeName(defel);
1899 177 395 : else if (strcmp(defel->defname, "stype1") == 0)
7664 178 15 : transType = defGetTypeName(defel);
1899 179 380 : else if (strcmp(defel->defname, "sspace") == 0)
3431 180 4 : transSpace = defGetInt32(defel);
1899 181 376 : else if (strcmp(defel->defname, "mstype") == 0)
3284 182 30 : mtransType = defGetTypeName(defel);
1899 183 346 : else if (strcmp(defel->defname, "msspace") == 0)
3284 tgl 184 LBC 0 : mtransSpace = defGetInt32(defel);
1899 tgl 185 GBC 346 : else if (strcmp(defel->defname, "initcond") == 0)
7664 tgl 186 CBC 279 : initval = defGetString(defel);
1899 187 67 : else if (strcmp(defel->defname, "initcond1") == 0)
7664 188 9 : initval = defGetString(defel);
1899 189 58 : else if (strcmp(defel->defname, "minitcond") == 0)
3284 190 8 : minitval = defGetString(defel);
1899 191 50 : else if (strcmp(defel->defname, "parallel") == 0)
2560 rhaas 192 17 : parallel = defGetString(defel);
7664 tgl 193 ECB : else
7203 tgl 194 GIC 33 : ereport(WARNING,
7203 tgl 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 : */
7664 tgl 203 GIC 449 : if (transType == NULL)
7203 tgl 204 CBC 6 : ereport(ERROR,
7203 tgl 205 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
206 : errmsg("aggregate stype must be specified")));
7664 tgl 207 GIC 443 : if (transfuncName == NIL)
7203 tgl 208 LBC 0 : ereport(ERROR,
7203 tgl 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 : */
3284 tgl 217 GIC 443 : if (mtransType != NULL)
3284 tgl 218 ECB : {
3284 tgl 219 GIC 30 : if (mtransfuncName == NIL)
3284 tgl 220 LBC 0 : ereport(ERROR,
3284 tgl 221 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
222 : errmsg("aggregate msfunc must be specified when mstype is specified")));
3284 tgl 223 GIC 30 : if (minvtransfuncName == NIL)
3284 tgl 224 LBC 0 : ereport(ERROR,
3284 tgl 225 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
226 : errmsg("aggregate minvfunc must be specified when mstype is specified")));
227 : }
228 : else
229 : {
3284 tgl 230 GIC 413 : if (mtransfuncName != NIL)
3284 tgl 231 LBC 0 : ereport(ERROR,
3284 tgl 232 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 : errmsg("aggregate msfunc must not be specified without mstype")));
3284 tgl 234 GIC 413 : if (minvtransfuncName != NIL)
3284 tgl 235 LBC 0 : ereport(ERROR,
3284 tgl 236 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 : errmsg("aggregate minvfunc must not be specified without mstype")));
3284 tgl 238 GIC 413 : if (mfinalfuncName != NIL)
3284 tgl 239 LBC 0 : ereport(ERROR,
3284 tgl 240 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241 : errmsg("aggregate mfinalfunc must not be specified without mstype")));
3284 tgl 242 GIC 413 : if (mtransSpace != 0)
3284 tgl 243 LBC 0 : ereport(ERROR,
3284 tgl 244 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
245 : errmsg("aggregate msspace must not be specified without mstype")));
3284 tgl 246 GIC 413 : if (minitval != NULL)
3284 tgl 247 LBC 0 : ereport(ERROR,
3284 tgl 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 : */
2003 tgl 256 GIC 443 : if (finalfuncModify == 0)
2003 tgl 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;
2003 tgl 260 ECB :
261 : /*
262 : * look up the aggregate's input datatype(s).
263 : */
6203 tgl 264 GIC 443 : if (oldstyle)
6203 tgl 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 :
6203 tgl 275 GIC 178 : if (baseType == NULL)
6203 tgl 276 CBC 3 : ereport(ERROR,
6203 tgl 277 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
278 : errmsg("aggregate input type must be specified")));
279 :
6203 tgl 280 GIC 175 : if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
6100 tgl 281 ECB : {
6100 tgl 282 GIC 3 : numArgs = 0;
3505 tgl 283 CBC 3 : aggArgTypes[0] = InvalidOid;
6100 tgl 284 ECB : }
285 : else
286 : {
6100 tgl 287 GIC 172 : numArgs = 1;
4549 peter_e 288 CBC 172 : aggArgTypes[0] = typenameTypeId(NULL, baseType);
6100 tgl 289 ECB : }
3505 tgl 290 GIC 175 : parameterTypes = buildoidvector(aggArgTypes, numArgs);
3505 tgl 291 CBC 175 : allParameterTypes = NULL;
292 175 : parameterModes = NULL;
293 175 : parameterNames = NULL;
294 175 : parameterDefaults = NIL;
3394 295 175 : variadicArgType = InvalidOid;
6203 tgl 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 :
6203 tgl 305 GIC 265 : if (baseType != NULL)
6203 tgl 306 LBC 0 : ereport(ERROR,
6203 tgl 307 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
308 : errmsg("basetype is redundant with aggregate input type specification")));
309 :
6100 tgl 310 GIC 265 : numArgs = list_length(args);
2406 peter_e 311 CBC 265 : interpret_function_parameter_list(pstate,
2406 peter_e 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 */
3505 tgl 325 GIC 262 : Assert(parameterDefaults == NIL);
3505 tgl 326 ECB : /* There shouldn't have been any OUT parameters, either */
3505 tgl 327 GIC 262 : Assert(requiredResultType == InvalidOid);
6203 tgl 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 : */
4549 peter_e 341 GIC 437 : transTypeId = typenameTypeId(NULL, transType);
3839 tgl 342 CBC 437 : transTypeType = get_typtype(transTypeId);
343 437 : if (transTypeType == TYPTYPE_PSEUDO &&
5851 344 137 : !IsPolymorphicType(transTypeId))
5259 tgl 345 ECB : {
5259 tgl 346 GIC 29 : if (transTypeId == INTERNALOID && superuser())
5050 bruce 347 ECB : /* okay */ ;
348 : else
5259 tgl 349 UIC 0 : ereport(ERROR,
5259 tgl 350 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351 : errmsg("aggregate transition data type cannot be %s",
352 : format_type_be(transTypeId))));
353 : }
354 :
2482 tgl 355 GIC 437 : if (serialfuncName && deserialfuncName)
2567 rhaas 356 ECB : {
357 : /*
358 : * Serialization is only needed/allowed for transtype INTERNAL.
359 : */
2567 rhaas 360 GIC 15 : if (transTypeId != INTERNALOID)
2567 rhaas 361 LBC 0 : ereport(ERROR,
2567 rhaas 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 : }
2482 tgl 366 GIC 422 : else if (serialfuncName || deserialfuncName)
2567 rhaas 367 ECB : {
368 : /*
369 : * Cannot specify one function without the other.
370 : */
2482 tgl 371 GIC 3 : ereport(ERROR,
2482 tgl 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 : */
3284 tgl 380 GIC 434 : if (mtransType)
3284 tgl 381 ECB : {
3284 tgl 382 GIC 30 : mtransTypeId = typenameTypeId(NULL, mtransType);
3284 tgl 383 CBC 30 : mtransTypeType = get_typtype(mtransTypeId);
384 30 : if (mtransTypeType == TYPTYPE_PSEUDO &&
3284 tgl 385 LBC 0 : !IsPolymorphicType(mtransTypeId))
3284 tgl 386 EUB : {
3284 tgl 387 UIC 0 : if (mtransTypeId == INTERNALOID && superuser())
3284 tgl 388 EUB : /* okay */ ;
389 : else
3284 tgl 390 UIC 0 : ereport(ERROR,
3284 tgl 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 : */
3839 tgl 406 GIC 434 : if (initval && transTypeType != TYPTYPE_PSEUDO)
3839 tgl 407 ECB : {
408 : Oid typinput,
409 : typioparam;
410 :
3839 tgl 411 GIC 185 : getTypeInputInfo(transTypeId, &typinput, &typioparam);
3839 tgl 412 CBC 185 : (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
3839 tgl 413 ECB : }
414 :
415 : /*
416 : * Likewise for moving-aggregate initval.
417 : */
3284 tgl 418 GIC 434 : if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
3284 tgl 419 ECB : {
420 : Oid typinput,
421 : typioparam;
422 :
3284 tgl 423 GIC 8 : getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
3284 tgl 424 CBC 8 : (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
3284 tgl 425 ECB : }
426 :
2560 rhaas 427 GIC 434 : if (parallel)
2560 rhaas 428 ECB : {
1899 tgl 429 GIC 17 : if (strcmp(parallel, "safe") == 0)
2560 rhaas 430 CBC 14 : proparallel = PROPARALLEL_SAFE;
1899 tgl 431 3 : else if (strcmp(parallel, "restricted") == 0)
2560 rhaas 432 LBC 0 : proparallel = PROPARALLEL_RESTRICTED;
1899 tgl 433 GBC 3 : else if (strcmp(parallel, "unsafe") == 0)
2560 rhaas 434 LBC 0 : proparallel = PROPARALLEL_UNSAFE;
2560 rhaas 435 EUB : else
2560 rhaas 436 GIC 3 : ereport(ERROR,
2560 rhaas 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 : */
2118 tgl 444 GIC 431 : return AggregateCreate(aggName, /* aggregate name */
2118 tgl 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
2003 tgl 482 GIC 10 : extractModify(DefElem *defel)
2003 tgl 483 ECB : {
2003 tgl 484 GIC 10 : char *val = defGetString(defel);
2003 tgl 485 ECB :
2003 tgl 486 GIC 10 : if (strcmp(val, "read_only") == 0)
2003 tgl 487 LBC 0 : return AGGMODIFY_READ_ONLY;
1784 tgl 488 GBC 10 : if (strcmp(val, "shareable") == 0)
1784 tgl 489 CBC 7 : return AGGMODIFY_SHAREABLE;
2003 490 3 : if (strcmp(val, "read_write") == 0)
491 3 : return AGGMODIFY_READ_WRITE;
2003 tgl 492 LBC 0 : ereport(ERROR,
2003 tgl 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 : }
|