59{
60 char *aggName;
63 char aggKind = AGGKIND_NORMAL;
72 bool finalfuncExtraArgs = false;
73 bool mfinalfuncExtraArgs = false;
74 char finalfuncModify = 0;
75 char mfinalfuncModify = 0;
81 int32 mtransSpace = 0;
82 char *initval = NULL;
83 char *minitval = NULL;
84 char *parallel = NULL;
85 int numArgs;
86 int numDirectArgs = 0;
91 List *parameterDefaults;
95 char transTypeType;
96 char mtransTypeType = 0;
97 char proparallel = PROPARALLEL_UNSAFE;
99
100 /* Convert list of names to a name and namespace */
102
103 /* Check we have creation rights in target namespace */
108
109 /* Deconstruct the output of the aggr_args grammar production */
110 if (!oldstyle)
111 {
114 if (numDirectArgs >= 0)
115 aggKind = AGGKIND_ORDERED_SET;
116 else
117 numDirectArgs = 0;
119 }
120
121 /* Examine aggregate's definition clauses */
122 foreach(pl, parameters)
123 {
125
126 /*
127 * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
128 * for sfunc, stype, initcond.
129 */
130 if (strcmp(defel->
defname,
"sfunc") == 0)
132 else if (strcmp(defel->
defname,
"sfunc1") == 0)
134 else if (strcmp(defel->
defname,
"finalfunc") == 0)
136 else if (strcmp(defel->
defname,
"combinefunc") == 0)
138 else if (strcmp(defel->
defname,
"serialfunc") == 0)
140 else if (strcmp(defel->
defname,
"deserialfunc") == 0)
142 else if (strcmp(defel->
defname,
"msfunc") == 0)
144 else if (strcmp(defel->
defname,
"minvfunc") == 0)
146 else if (strcmp(defel->
defname,
"mfinalfunc") == 0)
148 else if (strcmp(defel->
defname,
"finalfunc_extra") == 0)
150 else if (strcmp(defel->
defname,
"mfinalfunc_extra") == 0)
152 else if (strcmp(defel->
defname,
"finalfunc_modify") == 0)
154 else if (strcmp(defel->
defname,
"mfinalfunc_modify") == 0)
156 else if (strcmp(defel->
defname,
"sortop") == 0)
158 else if (strcmp(defel->
defname,
"basetype") == 0)
160 else if (strcmp(defel->
defname,
"hypothetical") == 0)
161 {
163 {
164 if (aggKind == AGGKIND_NORMAL)
166 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
167 errmsg(
"only ordered-set aggregates can be hypothetical")));
168 aggKind = AGGKIND_HYPOTHETICAL;
169 }
170 }
171 else if (strcmp(defel->
defname,
"stype") == 0)
173 else if (strcmp(defel->
defname,
"stype1") == 0)
175 else if (strcmp(defel->
defname,
"sspace") == 0)
177 else if (strcmp(defel->
defname,
"mstype") == 0)
179 else if (strcmp(defel->
defname,
"msspace") == 0)
181 else if (strcmp(defel->
defname,
"initcond") == 0)
183 else if (strcmp(defel->
defname,
"initcond1") == 0)
185 else if (strcmp(defel->
defname,
"minitcond") == 0)
187 else if (strcmp(defel->
defname,
"parallel") == 0)
189 else
191 (
errcode(ERRCODE_SYNTAX_ERROR),
192 errmsg(
"aggregate attribute \"%s\" not recognized",
194 }
195
196 /*
197 * make sure we have our required definitions
198 */
199 if (transType == NULL)
201 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
202 errmsg(
"aggregate stype must be specified")));
203 if (transfuncName ==
NIL)
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 */
213 if (mtransType != NULL)
214 {
215 if (mtransfuncName ==
NIL)
217 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
218 errmsg(
"aggregate msfunc must be specified when mstype is specified")));
219 if (minvtransfuncName ==
NIL)
221 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
222 errmsg(
"aggregate minvfunc must be specified when mstype is specified")));
223 }
224 else
225 {
226 if (mtransfuncName !=
NIL)
228 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229 errmsg(
"aggregate msfunc must not be specified without mstype")));
230 if (minvtransfuncName !=
NIL)
232 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 errmsg(
"aggregate minvfunc must not be specified without mstype")));
234 if (mfinalfuncName !=
NIL)
236 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 errmsg(
"aggregate mfinalfunc must not be specified without mstype")));
238 if (mtransSpace != 0)
240 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241 errmsg(
"aggregate msspace must not be specified without mstype")));
242 if (minitval != NULL)
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 */
252 if (finalfuncModify == 0)
253 finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
254 if (mfinalfuncModify == 0)
255 mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
256
257 /*
258 * look up the aggregate's input datatype(s).
259 */
260 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 */
270
271 if (baseType == NULL)
273 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
274 errmsg(
"aggregate input type must be specified")));
275
277 {
278 numArgs = 0;
280 }
281 else
282 {
283 numArgs = 1;
285 }
287 allParameterTypes = NULL;
288 parameterModes = NULL;
289 parameterNames = NULL;
290 parameterDefaults =
NIL;
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
301 if (baseType != NULL)
303 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
304 errmsg(
"basetype is redundant with aggregate input type specification")));
305
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 */
322 /* There shouldn't have been any OUT parameters, either */
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 */
339 if (transTypeType == TYPTYPE_PSEUDO &&
340 !IsPolymorphicType(transTypeId))
341 {
342 if (transTypeId == INTERNALOID &&
superuser())
343 /* okay */ ;
344 else
346 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
347 errmsg(
"aggregate transition data type cannot be %s",
349 }
350
351 if (serialfuncName && deserialfuncName)
352 {
353 /*
354 * Serialization is only needed/allowed for transtype INTERNAL.
355 */
356 if (transTypeId != INTERNALOID)
358 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
359 errmsg(
"serialization functions may be specified only when the aggregate transition data type is %s",
361 }
362 else if (serialfuncName || deserialfuncName)
363 {
364 /*
365 * Cannot specify one function without the other.
366 */
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 */
376 if (mtransType)
377 {
380 if (mtransTypeType == TYPTYPE_PSEUDO &&
381 !IsPolymorphicType(mtransTypeId))
382 {
383 if (mtransTypeId == INTERNALOID &&
superuser())
384 /* okay */ ;
385 else
387 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
388 errmsg(
"aggregate transition data type cannot be %s",
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 */
402 if (initval && transTypeType != TYPTYPE_PSEUDO)
403 {
405 typioparam;
406
409 }
410
411 /*
412 * Likewise for moving-aggregate initval.
413 */
414 if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
415 {
417 typioparam;
418
421 }
422
423 if (parallel)
424 {
425 if (strcmp(parallel, "safe") == 0)
426 proparallel = PROPARALLEL_SAFE;
427 else if (strcmp(parallel, "restricted") == 0)
428 proparallel = PROPARALLEL_RESTRICTED;
429 else if (strcmp(parallel, "unsafe") == 0)
430 proparallel = PROPARALLEL_UNSAFE;
431 else
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 */
441 aggNamespace, /* namespace */
442 replace,
443 aggKind,
444 numArgs,
445 numDirectArgs,
446 parameterTypes,
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}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
static char extractModify(DefElem *defel)
TypeName * defGetTypeName(DefElem *def)
int32 defGetInt32(DefElem *def)
char * defGetString(DefElem *def)
bool defGetBoolean(DefElem *def)
List * defGetQualifiedName(DefElem *def)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
void interpret_function_parameter_list(ParseState *pstate, List *parameters, Oid languageOid, ObjectType objtype, oidvector **parameterTypes, List **parameterTypes_list, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **inParameterNames_list, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
Assert(PointerIsAligned(start, uint64))
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
char get_typtype(Oid typid)
char * get_namespace_name(Oid nspid)
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
oidvector * buildoidvector(const Oid *oids, int n)
char * TypeNameToString(const TypeName *typeName)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
ObjectAddress AggregateCreate(const char *aggName, Oid aggNamespace, bool replace, char aggKind, int numArgs, int numDirectArgs, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Oid variadicArgType, List *aggtransfnName, List *aggfinalfnName, List *aggcombinefnName, List *aggserialfnName, List *aggdeserialfnName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, char finalfnModify, char mfinalfnModify, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define linitial_node(type, l)
int pg_strcasecmp(const char *s1, const char *s2)
static Datum PointerGetDatum(const void *X)