1 /*-------------------------------------------------------------------------
2  *
3  * aggregatecmds.c
4  *
5  *	  Routines for aggregate-manipulation commands
6  *
7  * Portions Copyright (c) 1996-2016, 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/heapam.h"
26 #include "access/htup_details.h"
27 #include "catalog/dependency.h"
28 #include "catalog/indexing.h"
29 #include "catalog/pg_aggregate.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_type.h"
32 #include "commands/alter.h"
33 #include "commands/defrem.h"
34 #include "miscadmin.h"
35 #include "parser/parse_func.h"
36 #include "parser/parse_type.h"
37 #include "utils/acl.h"
38 #include "utils/builtins.h"
39 #include "utils/lsyscache.h"
40 #include "utils/syscache.h"
41 
42 
43 /*
44  *	DefineAggregate
45  *
46  * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
47  * is specified by a BASETYPE element in the parameters.  Otherwise,
48  * "args" is a pair, whose first element is a list of FunctionParameter structs
49  * defining the agg's arguments (both direct and aggregated), and whose second
50  * element is an Integer node with the number of direct args, or -1 if this
51  * isn't an ordered-set aggregate.
52  * "parameters" is a list of DefElem representing the agg's definition clauses.
53  */
54 ObjectAddress
DefineAggregate(List * name,List * args,bool oldstyle,List * parameters,const char * queryString)55 DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
56 				const char *queryString)
57 {
58 	char	   *aggName;
59 	Oid			aggNamespace;
60 	AclResult	aclresult;
61 	char		aggKind = AGGKIND_NORMAL;
62 	List	   *transfuncName = NIL;
63 	List	   *finalfuncName = NIL;
64 	List	   *combinefuncName = NIL;
65 	List	   *serialfuncName = NIL;
66 	List	   *deserialfuncName = NIL;
67 	List	   *mtransfuncName = NIL;
68 	List	   *minvtransfuncName = NIL;
69 	List	   *mfinalfuncName = NIL;
70 	bool		finalfuncExtraArgs = false;
71 	bool		mfinalfuncExtraArgs = false;
72 	List	   *sortoperatorName = NIL;
73 	TypeName   *baseType = NULL;
74 	TypeName   *transType = NULL;
75 	TypeName   *mtransType = NULL;
76 	int32		transSpace = 0;
77 	int32		mtransSpace = 0;
78 	char	   *initval = NULL;
79 	char	   *minitval = NULL;
80 	char	   *parallel = NULL;
81 	int			numArgs;
82 	int			numDirectArgs = 0;
83 	oidvector  *parameterTypes;
84 	ArrayType  *allParameterTypes;
85 	ArrayType  *parameterModes;
86 	ArrayType  *parameterNames;
87 	List	   *parameterDefaults;
88 	Oid			variadicArgType;
89 	Oid			transTypeId;
90 	Oid			mtransTypeId = InvalidOid;
91 	char		transTypeType;
92 	char		mtransTypeType = 0;
93 	char		proparallel = PROPARALLEL_UNSAFE;
94 	ListCell   *pl;
95 
96 	/* Convert list of names to a name and namespace */
97 	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
98 
99 	/* Check we have creation rights in target namespace */
100 	aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
101 	if (aclresult != ACLCHECK_OK)
102 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
103 					   get_namespace_name(aggNamespace));
104 
105 	/* Deconstruct the output of the aggr_args grammar production */
106 	if (!oldstyle)
107 	{
108 		Assert(list_length(args) == 2);
109 		numDirectArgs = intVal(lsecond(args));
110 		if (numDirectArgs >= 0)
111 			aggKind = AGGKIND_ORDERED_SET;
112 		else
113 			numDirectArgs = 0;
114 		args = (List *) linitial(args);
115 	}
116 
117 	/* Examine aggregate's definition clauses */
118 	foreach(pl, parameters)
119 	{
120 		DefElem    *defel = (DefElem *) lfirst(pl);
121 
122 		/*
123 		 * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
124 		 * for sfunc, stype, initcond.
125 		 */
126 		if (pg_strcasecmp(defel->defname, "sfunc") == 0)
127 			transfuncName = defGetQualifiedName(defel);
128 		else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
129 			transfuncName = defGetQualifiedName(defel);
130 		else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
131 			finalfuncName = defGetQualifiedName(defel);
132 		else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
133 			combinefuncName = defGetQualifiedName(defel);
134 		else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
135 			serialfuncName = defGetQualifiedName(defel);
136 		else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
137 			deserialfuncName = defGetQualifiedName(defel);
138 		else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
139 			mtransfuncName = defGetQualifiedName(defel);
140 		else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
141 			minvtransfuncName = defGetQualifiedName(defel);
142 		else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
143 			mfinalfuncName = defGetQualifiedName(defel);
144 		else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
145 			finalfuncExtraArgs = defGetBoolean(defel);
146 		else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
147 			mfinalfuncExtraArgs = defGetBoolean(defel);
148 		else if (pg_strcasecmp(defel->defname, "sortop") == 0)
149 			sortoperatorName = defGetQualifiedName(defel);
150 		else if (pg_strcasecmp(defel->defname, "basetype") == 0)
151 			baseType = defGetTypeName(defel);
152 		else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
153 		{
154 			if (defGetBoolean(defel))
155 			{
156 				if (aggKind == AGGKIND_NORMAL)
157 					ereport(ERROR,
158 							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
159 							 errmsg("only ordered-set aggregates can be hypothetical")));
160 				aggKind = AGGKIND_HYPOTHETICAL;
161 			}
162 		}
163 		else if (pg_strcasecmp(defel->defname, "stype") == 0)
164 			transType = defGetTypeName(defel);
165 		else if (pg_strcasecmp(defel->defname, "stype1") == 0)
166 			transType = defGetTypeName(defel);
167 		else if (pg_strcasecmp(defel->defname, "sspace") == 0)
168 			transSpace = defGetInt32(defel);
169 		else if (pg_strcasecmp(defel->defname, "mstype") == 0)
170 			mtransType = defGetTypeName(defel);
171 		else if (pg_strcasecmp(defel->defname, "msspace") == 0)
172 			mtransSpace = defGetInt32(defel);
173 		else if (pg_strcasecmp(defel->defname, "initcond") == 0)
174 			initval = defGetString(defel);
175 		else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
176 			initval = defGetString(defel);
177 		else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
178 			minitval = defGetString(defel);
179 		else if (pg_strcasecmp(defel->defname, "parallel") == 0)
180 			parallel = defGetString(defel);
181 		else
182 			ereport(WARNING,
183 					(errcode(ERRCODE_SYNTAX_ERROR),
184 					 errmsg("aggregate attribute \"%s\" not recognized",
185 							defel->defname)));
186 	}
187 
188 	/*
189 	 * make sure we have our required definitions
190 	 */
191 	if (transType == NULL)
192 		ereport(ERROR,
193 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
194 				 errmsg("aggregate stype must be specified")));
195 	if (transfuncName == NIL)
196 		ereport(ERROR,
197 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
198 				 errmsg("aggregate sfunc must be specified")));
199 
200 	/*
201 	 * if mtransType is given, mtransfuncName and minvtransfuncName must be as
202 	 * well; if not, then none of the moving-aggregate options should have
203 	 * been given.
204 	 */
205 	if (mtransType != NULL)
206 	{
207 		if (mtransfuncName == NIL)
208 			ereport(ERROR,
209 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
210 					 errmsg("aggregate msfunc must be specified when mstype is specified")));
211 		if (minvtransfuncName == NIL)
212 			ereport(ERROR,
213 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
214 					 errmsg("aggregate minvfunc must be specified when mstype is specified")));
215 	}
216 	else
217 	{
218 		if (mtransfuncName != NIL)
219 			ereport(ERROR,
220 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
221 			errmsg("aggregate msfunc must not be specified without mstype")));
222 		if (minvtransfuncName != NIL)
223 			ereport(ERROR,
224 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
225 					 errmsg("aggregate minvfunc must not be specified without mstype")));
226 		if (mfinalfuncName != NIL)
227 			ereport(ERROR,
228 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229 					 errmsg("aggregate mfinalfunc must not be specified without mstype")));
230 		if (mtransSpace != 0)
231 			ereport(ERROR,
232 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 					 errmsg("aggregate msspace must not be specified without mstype")));
234 		if (minitval != NULL)
235 			ereport(ERROR,
236 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 					 errmsg("aggregate minitcond must not be specified without mstype")));
238 	}
239 
240 	/*
241 	 * look up the aggregate's input datatype(s).
242 	 */
243 	if (oldstyle)
244 	{
245 		/*
246 		 * Old style: use basetype parameter.  This supports aggregates of
247 		 * zero or one input, with input type ANY meaning zero inputs.
248 		 *
249 		 * Historically we allowed the command to look like basetype = 'ANY'
250 		 * so we must do a case-insensitive comparison for the name ANY. Ugh.
251 		 */
252 		Oid			aggArgTypes[1];
253 
254 		if (baseType == NULL)
255 			ereport(ERROR,
256 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
257 					 errmsg("aggregate input type must be specified")));
258 
259 		if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
260 		{
261 			numArgs = 0;
262 			aggArgTypes[0] = InvalidOid;
263 		}
264 		else
265 		{
266 			numArgs = 1;
267 			aggArgTypes[0] = typenameTypeId(NULL, baseType);
268 		}
269 		parameterTypes = buildoidvector(aggArgTypes, numArgs);
270 		allParameterTypes = NULL;
271 		parameterModes = NULL;
272 		parameterNames = NULL;
273 		parameterDefaults = NIL;
274 		variadicArgType = InvalidOid;
275 	}
276 	else
277 	{
278 		/*
279 		 * New style: args is a list of FunctionParameters (possibly zero of
280 		 * 'em).  We share functioncmds.c's code for processing them.
281 		 */
282 		Oid			requiredResultType;
283 
284 		if (baseType != NULL)
285 			ereport(ERROR,
286 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
287 					 errmsg("basetype is redundant with aggregate input type specification")));
288 
289 		numArgs = list_length(args);
290 		interpret_function_parameter_list(args,
291 										  InvalidOid,
292 										  true, /* is an aggregate */
293 										  queryString,
294 										  &parameterTypes,
295 										  &allParameterTypes,
296 										  &parameterModes,
297 										  &parameterNames,
298 										  &parameterDefaults,
299 										  &variadicArgType,
300 										  &requiredResultType);
301 		/* Parameter defaults are not currently allowed by the grammar */
302 		Assert(parameterDefaults == NIL);
303 		/* There shouldn't have been any OUT parameters, either */
304 		Assert(requiredResultType == InvalidOid);
305 	}
306 
307 	/*
308 	 * look up the aggregate's transtype.
309 	 *
310 	 * transtype can't be a pseudo-type, since we need to be able to store
311 	 * values of the transtype.  However, we can allow polymorphic transtype
312 	 * in some cases (AggregateCreate will check).  Also, we allow "internal"
313 	 * for functions that want to pass pointers to private data structures;
314 	 * but allow that only to superusers, since you could crash the system (or
315 	 * worse) by connecting up incompatible internal-using functions in an
316 	 * aggregate.
317 	 */
318 	transTypeId = typenameTypeId(NULL, transType);
319 	transTypeType = get_typtype(transTypeId);
320 	if (transTypeType == TYPTYPE_PSEUDO &&
321 		!IsPolymorphicType(transTypeId))
322 	{
323 		if (transTypeId == INTERNALOID && superuser())
324 			 /* okay */ ;
325 		else
326 			ereport(ERROR,
327 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
328 					 errmsg("aggregate transition data type cannot be %s",
329 							format_type_be(transTypeId))));
330 	}
331 
332 	if (serialfuncName && deserialfuncName)
333 	{
334 		/*
335 		 * Serialization is only needed/allowed for transtype INTERNAL.
336 		 */
337 		if (transTypeId != INTERNALOID)
338 			ereport(ERROR,
339 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
340 					 errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
341 							format_type_be(INTERNALOID))));
342 	}
343 	else if (serialfuncName || deserialfuncName)
344 	{
345 		/*
346 		 * Cannot specify one function without the other.
347 		 */
348 		ereport(ERROR,
349 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
350 				 errmsg("must specify both or neither of serialization and deserialization functions")));
351 	}
352 
353 	/*
354 	 * If a moving-aggregate transtype is specified, look that up.  Same
355 	 * restrictions as for transtype.
356 	 */
357 	if (mtransType)
358 	{
359 		mtransTypeId = typenameTypeId(NULL, mtransType);
360 		mtransTypeType = get_typtype(mtransTypeId);
361 		if (mtransTypeType == TYPTYPE_PSEUDO &&
362 			!IsPolymorphicType(mtransTypeId))
363 		{
364 			if (mtransTypeId == INTERNALOID && superuser())
365 				 /* okay */ ;
366 			else
367 				ereport(ERROR,
368 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
369 						 errmsg("aggregate transition data type cannot be %s",
370 								format_type_be(mtransTypeId))));
371 		}
372 	}
373 
374 	/*
375 	 * If we have an initval, and it's not for a pseudotype (particularly a
376 	 * polymorphic type), make sure it's acceptable to the type's input
377 	 * function.  We will store the initval as text, because the input
378 	 * function isn't necessarily immutable (consider "now" for timestamp),
379 	 * and we want to use the runtime not creation-time interpretation of the
380 	 * value.  However, if it's an incorrect value it seems much more
381 	 * user-friendly to complain at CREATE AGGREGATE time.
382 	 */
383 	if (initval && transTypeType != TYPTYPE_PSEUDO)
384 	{
385 		Oid			typinput,
386 					typioparam;
387 
388 		getTypeInputInfo(transTypeId, &typinput, &typioparam);
389 		(void) OidInputFunctionCall(typinput, initval, typioparam, -1);
390 	}
391 
392 	/*
393 	 * Likewise for moving-aggregate initval.
394 	 */
395 	if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
396 	{
397 		Oid			typinput,
398 					typioparam;
399 
400 		getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
401 		(void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
402 	}
403 
404 	if (parallel)
405 	{
406 		if (pg_strcasecmp(parallel, "safe") == 0)
407 			proparallel = PROPARALLEL_SAFE;
408 		else if (pg_strcasecmp(parallel, "restricted") == 0)
409 			proparallel = PROPARALLEL_RESTRICTED;
410 		else if (pg_strcasecmp(parallel, "unsafe") == 0)
411 			proparallel = PROPARALLEL_UNSAFE;
412 		else
413 			ereport(ERROR,
414 					(errcode(ERRCODE_SYNTAX_ERROR),
415 					 errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
416 	}
417 
418 	/*
419 	 * Most of the argument-checking is done inside of AggregateCreate
420 	 */
421 	return AggregateCreate(aggName,		/* aggregate name */
422 						   aggNamespace,		/* namespace */
423 						   aggKind,
424 						   numArgs,
425 						   numDirectArgs,
426 						   parameterTypes,
427 						   PointerGetDatum(allParameterTypes),
428 						   PointerGetDatum(parameterModes),
429 						   PointerGetDatum(parameterNames),
430 						   parameterDefaults,
431 						   variadicArgType,
432 						   transfuncName,		/* step function name */
433 						   finalfuncName,		/* final function name */
434 						   combinefuncName,		/* combine function name */
435 						   serialfuncName,		/* serial function name */
436 						   deserialfuncName,	/* deserial function name */
437 						   mtransfuncName,		/* fwd trans function name */
438 						   minvtransfuncName,	/* inv trans function name */
439 						   mfinalfuncName,		/* final function name */
440 						   finalfuncExtraArgs,
441 						   mfinalfuncExtraArgs,
442 						   sortoperatorName,	/* sort operator name */
443 						   transTypeId, /* transition data type */
444 						   transSpace,	/* transition space */
445 						   mtransTypeId,		/* transition data type */
446 						   mtransSpace, /* transition space */
447 						   initval,		/* initial condition */
448 						   minitval,	/* initial condition */
449 						   proparallel);		/* parallel safe? */
450 }
451