Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_aggregate.c
4 : * routines to support manipulation of the pg_aggregate relation
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/catalog/pg_aggregate.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/heapam.h"
18 : #include "access/htup_details.h"
19 : #include "catalog/dependency.h"
20 : #include "catalog/indexing.h"
21 : #include "catalog/pg_aggregate.h"
22 : #include "catalog/pg_language.h"
23 : #include "catalog/pg_operator.h"
24 : #include "catalog/pg_proc.h"
25 : #include "catalog/pg_proc_fn.h"
26 : #include "catalog/pg_type.h"
27 : #include "miscadmin.h"
28 : #include "parser/parse_coerce.h"
29 : #include "parser/parse_func.h"
30 : #include "parser/parse_oper.h"
31 : #include "utils/acl.h"
32 : #include "utils/builtins.h"
33 : #include "utils/lsyscache.h"
34 : #include "utils/rel.h"
35 : #include "utils/syscache.h"
36 :
37 :
38 : static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
39 : Oid variadicArgType,
40 : Oid *rettype);
41 :
42 :
43 : /*
44 : * AggregateCreate
45 : */
46 : ObjectAddress
47 115 : AggregateCreate(const char *aggName,
48 : Oid aggNamespace,
49 : char aggKind,
50 : int numArgs,
51 : int numDirectArgs,
52 : oidvector *parameterTypes,
53 : Datum allParameterTypes,
54 : Datum parameterModes,
55 : Datum parameterNames,
56 : List *parameterDefaults,
57 : Oid variadicArgType,
58 : List *aggtransfnName,
59 : List *aggfinalfnName,
60 : List *aggcombinefnName,
61 : List *aggserialfnName,
62 : List *aggdeserialfnName,
63 : List *aggmtransfnName,
64 : List *aggminvtransfnName,
65 : List *aggmfinalfnName,
66 : bool finalfnExtraArgs,
67 : bool mfinalfnExtraArgs,
68 : List *aggsortopName,
69 : Oid aggTransType,
70 : int32 aggTransSpace,
71 : Oid aggmTransType,
72 : int32 aggmTransSpace,
73 : const char *agginitval,
74 : const char *aggminitval,
75 : char proparallel)
76 : {
77 : Relation aggdesc;
78 : HeapTuple tup;
79 : bool nulls[Natts_pg_aggregate];
80 : Datum values[Natts_pg_aggregate];
81 : Form_pg_proc proc;
82 : Oid transfn;
83 115 : Oid finalfn = InvalidOid; /* can be omitted */
84 115 : Oid combinefn = InvalidOid; /* can be omitted */
85 115 : Oid serialfn = InvalidOid; /* can be omitted */
86 115 : Oid deserialfn = InvalidOid; /* can be omitted */
87 115 : Oid mtransfn = InvalidOid; /* can be omitted */
88 115 : Oid minvtransfn = InvalidOid; /* can be omitted */
89 115 : Oid mfinalfn = InvalidOid; /* can be omitted */
90 115 : Oid sortop = InvalidOid; /* can be omitted */
91 115 : Oid *aggArgTypes = parameterTypes->values;
92 : bool hasPolyArg;
93 : bool hasInternalArg;
94 115 : bool mtransIsStrict = false;
95 : Oid rettype;
96 : Oid finaltype;
97 : Oid fnArgs[FUNC_MAX_ARGS];
98 : int nargs_transfn;
99 : int nargs_finalfn;
100 : Oid procOid;
101 : TupleDesc tupDesc;
102 : int i;
103 : ObjectAddress myself,
104 : referenced;
105 : AclResult aclresult;
106 :
107 : /* sanity checks (caller should have caught these) */
108 115 : if (!aggName)
109 0 : elog(ERROR, "no aggregate name supplied");
110 :
111 115 : if (!aggtransfnName)
112 0 : elog(ERROR, "aggregate must have a transition function");
113 :
114 115 : if (numDirectArgs < 0 || numDirectArgs > numArgs)
115 0 : elog(ERROR, "incorrect number of direct args for aggregate");
116 :
117 : /*
118 : * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
119 : * and/or finalfn will be unrepresentable in pg_proc. We must check now
120 : * to protect fixed-size arrays here and possibly in called functions.
121 : */
122 115 : if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
123 0 : ereport(ERROR,
124 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
125 : errmsg_plural("aggregates cannot have more than %d argument",
126 : "aggregates cannot have more than %d arguments",
127 : FUNC_MAX_ARGS - 1,
128 : FUNC_MAX_ARGS - 1)));
129 :
130 : /* check for polymorphic and INTERNAL arguments */
131 115 : hasPolyArg = false;
132 115 : hasInternalArg = false;
133 226 : for (i = 0; i < numArgs; i++)
134 : {
135 111 : if (IsPolymorphicType(aggArgTypes[i]))
136 34 : hasPolyArg = true;
137 77 : else if (aggArgTypes[i] == INTERNALOID)
138 0 : hasInternalArg = true;
139 : }
140 :
141 : /*
142 : * If transtype is polymorphic, must have polymorphic argument also; else
143 : * we will have no way to deduce the actual transtype.
144 : */
145 115 : if (IsPolymorphicType(aggTransType) && !hasPolyArg)
146 18 : ereport(ERROR,
147 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
148 : errmsg("cannot determine transition data type"),
149 : errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
150 :
151 : /*
152 : * Likewise for moving-aggregate transtype, if any
153 : */
154 97 : if (OidIsValid(aggmTransType) &&
155 8 : IsPolymorphicType(aggmTransType) && !hasPolyArg)
156 0 : ereport(ERROR,
157 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
158 : errmsg("cannot determine transition data type"),
159 : errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
160 :
161 : /*
162 : * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
163 : * principle we could support regular variadic types, but it would make
164 : * things much more complicated because we'd have to assemble the correct
165 : * subsets of arguments into array values. Since no standard aggregates
166 : * have use for such a case, we aren't bothering for now.
167 : */
168 97 : if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
169 : variadicArgType != ANYOID)
170 0 : ereport(ERROR,
171 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
172 : errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
173 :
174 : /*
175 : * If it's a hypothetical-set aggregate, there must be at least as many
176 : * direct arguments as aggregated ones, and the last N direct arguments
177 : * must match the aggregated ones in type. (We have to check this again
178 : * when the aggregate is called, in case ANY is involved, but it makes
179 : * sense to reject the aggregate definition now if the declared arg types
180 : * don't match up.) It's unconditionally OK if numDirectArgs == numArgs,
181 : * indicating that the grammar merged identical VARIADIC entries from both
182 : * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
183 : * the aggregated side, which is not OK. Otherwise, insist on the last N
184 : * parameter types on each side matching exactly.
185 : */
186 97 : if (aggKind == AGGKIND_HYPOTHETICAL &&
187 : numDirectArgs < numArgs)
188 : {
189 0 : int numAggregatedArgs = numArgs - numDirectArgs;
190 :
191 0 : if (OidIsValid(variadicArgType) ||
192 0 : numDirectArgs < numAggregatedArgs ||
193 0 : memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
194 0 : aggArgTypes + numDirectArgs,
195 : numAggregatedArgs * sizeof(Oid)) != 0)
196 0 : ereport(ERROR,
197 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
198 : errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
199 : }
200 :
201 : /*
202 : * Find the transfn. For ordinary aggs, it takes the transtype plus all
203 : * aggregate arguments. For ordered-set aggs, it takes the transtype plus
204 : * all aggregated args, but not direct args. However, we have to treat
205 : * specially the case where a trailing VARIADIC item is considered to
206 : * cover both direct and aggregated args.
207 : */
208 97 : if (AGGKIND_IS_ORDERED_SET(aggKind))
209 : {
210 2 : if (numDirectArgs < numArgs)
211 1 : nargs_transfn = numArgs - numDirectArgs + 1;
212 : else
213 : {
214 : /* special case with VARIADIC last arg */
215 1 : Assert(variadicArgType != InvalidOid);
216 1 : nargs_transfn = 2;
217 : }
218 2 : fnArgs[0] = aggTransType;
219 2 : memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
220 : (nargs_transfn - 1) * sizeof(Oid));
221 : }
222 : else
223 : {
224 95 : nargs_transfn = numArgs + 1;
225 95 : fnArgs[0] = aggTransType;
226 95 : memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
227 : }
228 97 : transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
229 : fnArgs, variadicArgType,
230 : &rettype);
231 :
232 : /*
233 : * Return type of transfn (possibly after refinement by
234 : * enforce_generic_type_consistency, if transtype isn't polymorphic) must
235 : * exactly match declared transtype.
236 : *
237 : * In the non-polymorphic-transtype case, it might be okay to allow a
238 : * rettype that's binary-coercible to transtype, but I'm not quite
239 : * convinced that it's either safe or useful. When transtype is
240 : * polymorphic we *must* demand exact equality.
241 : */
242 78 : if (rettype != aggTransType)
243 0 : ereport(ERROR,
244 : (errcode(ERRCODE_DATATYPE_MISMATCH),
245 : errmsg("return type of transition function %s is not %s",
246 : NameListToString(aggtransfnName),
247 : format_type_be(aggTransType))));
248 :
249 78 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
250 78 : if (!HeapTupleIsValid(tup))
251 0 : elog(ERROR, "cache lookup failed for function %u", transfn);
252 78 : proc = (Form_pg_proc) GETSTRUCT(tup);
253 :
254 : /*
255 : * If the transfn is strict and the initval is NULL, make sure first input
256 : * type and transtype are the same (or at least binary-compatible), so
257 : * that it's OK to use the first input value as the initial transValue.
258 : */
259 78 : if (proc->proisstrict && agginitval == NULL)
260 : {
261 12 : if (numArgs < 1 ||
262 6 : !IsBinaryCoercible(aggArgTypes[0], aggTransType))
263 0 : ereport(ERROR,
264 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
265 : errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
266 : }
267 :
268 78 : ReleaseSysCache(tup);
269 :
270 : /* handle moving-aggregate transfn, if supplied */
271 78 : if (aggmtransfnName)
272 : {
273 : /*
274 : * The arguments are the same as for the regular transfn, except that
275 : * the transition data type might be different. So re-use the fnArgs
276 : * values set up above, except for that one.
277 : */
278 8 : Assert(OidIsValid(aggmTransType));
279 8 : fnArgs[0] = aggmTransType;
280 :
281 8 : mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
282 : fnArgs, variadicArgType,
283 : &rettype);
284 :
285 : /* As above, return type must exactly match declared mtranstype. */
286 8 : if (rettype != aggmTransType)
287 0 : ereport(ERROR,
288 : (errcode(ERRCODE_DATATYPE_MISMATCH),
289 : errmsg("return type of transition function %s is not %s",
290 : NameListToString(aggmtransfnName),
291 : format_type_be(aggmTransType))));
292 :
293 8 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
294 8 : if (!HeapTupleIsValid(tup))
295 0 : elog(ERROR, "cache lookup failed for function %u", mtransfn);
296 8 : proc = (Form_pg_proc) GETSTRUCT(tup);
297 :
298 : /*
299 : * If the mtransfn is strict and the minitval is NULL, check first
300 : * input type and mtranstype are binary-compatible.
301 : */
302 8 : if (proc->proisstrict && aggminitval == NULL)
303 : {
304 10 : if (numArgs < 1 ||
305 5 : !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
306 0 : ereport(ERROR,
307 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
308 : errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
309 : }
310 :
311 : /* Remember if mtransfn is strict; we may need this below */
312 8 : mtransIsStrict = proc->proisstrict;
313 :
314 8 : ReleaseSysCache(tup);
315 : }
316 :
317 : /* handle minvtransfn, if supplied */
318 78 : if (aggminvtransfnName)
319 : {
320 : /*
321 : * This must have the same number of arguments with the same types as
322 : * the forward transition function, so just re-use the fnArgs data.
323 : */
324 8 : Assert(aggmtransfnName);
325 :
326 8 : minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
327 : fnArgs, variadicArgType,
328 : &rettype);
329 :
330 : /* As above, return type must exactly match declared mtranstype. */
331 8 : if (rettype != aggmTransType)
332 1 : ereport(ERROR,
333 : (errcode(ERRCODE_DATATYPE_MISMATCH),
334 : errmsg("return type of inverse transition function %s is not %s",
335 : NameListToString(aggminvtransfnName),
336 : format_type_be(aggmTransType))));
337 :
338 7 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
339 7 : if (!HeapTupleIsValid(tup))
340 0 : elog(ERROR, "cache lookup failed for function %u", minvtransfn);
341 7 : proc = (Form_pg_proc) GETSTRUCT(tup);
342 :
343 : /*
344 : * We require the strictness settings of the forward and inverse
345 : * transition functions to agree. This saves having to handle
346 : * assorted special cases at execution time.
347 : */
348 7 : if (proc->proisstrict != mtransIsStrict)
349 1 : ereport(ERROR,
350 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351 : errmsg("strictness of aggregate's forward and inverse transition functions must match")));
352 :
353 6 : ReleaseSysCache(tup);
354 : }
355 :
356 : /* handle finalfn, if supplied */
357 76 : if (aggfinalfnName)
358 : {
359 : /*
360 : * If finalfnExtraArgs is specified, the transfn takes the transtype
361 : * plus all args; otherwise, it just takes the transtype plus any
362 : * direct args. (Non-direct args are useless at runtime, and are
363 : * actually passed as NULLs, but we may need them in the function
364 : * signature to allow resolution of a polymorphic agg's result type.)
365 : */
366 29 : Oid ffnVariadicArgType = variadicArgType;
367 :
368 29 : fnArgs[0] = aggTransType;
369 29 : memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
370 29 : if (finalfnExtraArgs)
371 2 : nargs_finalfn = numArgs + 1;
372 : else
373 : {
374 27 : nargs_finalfn = numDirectArgs + 1;
375 27 : if (numDirectArgs < numArgs)
376 : {
377 : /* variadic argument doesn't affect finalfn */
378 23 : ffnVariadicArgType = InvalidOid;
379 : }
380 : }
381 :
382 29 : finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
383 : fnArgs, ffnVariadicArgType,
384 : &finaltype);
385 :
386 : /*
387 : * When finalfnExtraArgs is specified, the finalfn will certainly be
388 : * passed at least one null argument, so complain if it's strict.
389 : * Nothing bad would happen at runtime (you'd just get a null result),
390 : * but it's surely not what the user wants, so let's complain now.
391 : */
392 27 : if (finalfnExtraArgs && func_strict(finalfn))
393 0 : ereport(ERROR,
394 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
395 : errmsg("final function with extra arguments must not be declared STRICT")));
396 : }
397 : else
398 : {
399 : /*
400 : * If no finalfn, aggregate result type is type of the state value
401 : */
402 47 : finaltype = aggTransType;
403 : }
404 74 : Assert(OidIsValid(finaltype));
405 :
406 : /* handle the combinefn, if supplied */
407 74 : if (aggcombinefnName)
408 : {
409 : Oid combineType;
410 :
411 : /*
412 : * Combine function must have 2 argument, each of which is the trans
413 : * type
414 : */
415 2 : fnArgs[0] = aggTransType;
416 2 : fnArgs[1] = aggTransType;
417 :
418 2 : combinefn = lookup_agg_function(aggcombinefnName, 2, fnArgs,
419 : variadicArgType, &combineType);
420 :
421 : /* Ensure the return type matches the aggregates trans type */
422 1 : if (combineType != aggTransType)
423 0 : ereport(ERROR,
424 : (errcode(ERRCODE_DATATYPE_MISMATCH),
425 : errmsg("return type of combine function %s is not %s",
426 : NameListToString(aggcombinefnName),
427 : format_type_be(aggTransType))));
428 :
429 : /*
430 : * A combine function to combine INTERNAL states must accept nulls and
431 : * ensure that the returned state is in the correct memory context.
432 : */
433 1 : if (aggTransType == INTERNALOID && func_strict(combinefn))
434 0 : ereport(ERROR,
435 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
436 : errmsg("combine function with transition type %s must not be declared STRICT",
437 : format_type_be(aggTransType))));
438 :
439 : }
440 :
441 : /*
442 : * Validate the serialization function, if present.
443 : */
444 73 : if (aggserialfnName)
445 : {
446 3 : fnArgs[0] = INTERNALOID;
447 :
448 3 : serialfn = lookup_agg_function(aggserialfnName, 1,
449 : fnArgs, variadicArgType,
450 : &rettype);
451 :
452 2 : if (rettype != BYTEAOID)
453 0 : ereport(ERROR,
454 : (errcode(ERRCODE_DATATYPE_MISMATCH),
455 : errmsg("return type of serialization function %s is not %s",
456 : NameListToString(aggserialfnName),
457 : format_type_be(BYTEAOID))));
458 : }
459 :
460 : /*
461 : * Validate the deserialization function, if present.
462 : */
463 72 : if (aggdeserialfnName)
464 : {
465 2 : fnArgs[0] = BYTEAOID;
466 2 : fnArgs[1] = INTERNALOID; /* dummy argument for type safety */
467 :
468 2 : deserialfn = lookup_agg_function(aggdeserialfnName, 2,
469 : fnArgs, variadicArgType,
470 : &rettype);
471 :
472 1 : if (rettype != INTERNALOID)
473 0 : ereport(ERROR,
474 : (errcode(ERRCODE_DATATYPE_MISMATCH),
475 : errmsg("return type of deserialization function %s is not %s",
476 : NameListToString(aggdeserialfnName),
477 : format_type_be(INTERNALOID))));
478 : }
479 :
480 : /*
481 : * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
482 : * be polymorphic also, else parser will fail to deduce result type.
483 : * (Note: given the previous test on transtype and inputs, this cannot
484 : * happen, unless someone has snuck a finalfn definition into the catalogs
485 : * that itself violates the rule against polymorphic result with no
486 : * polymorphic input.)
487 : */
488 71 : if (IsPolymorphicType(finaltype) && !hasPolyArg)
489 0 : ereport(ERROR,
490 : (errcode(ERRCODE_DATATYPE_MISMATCH),
491 : errmsg("cannot determine result data type"),
492 : errdetail("An aggregate returning a polymorphic type "
493 : "must have at least one polymorphic argument.")));
494 :
495 : /*
496 : * Also, the return type can't be INTERNAL unless there's at least one
497 : * INTERNAL argument. This is the same type-safety restriction we enforce
498 : * for regular functions, but at the level of aggregates. We must test
499 : * this explicitly because we allow INTERNAL as the transtype.
500 : */
501 71 : if (finaltype == INTERNALOID && !hasInternalArg)
502 0 : ereport(ERROR,
503 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
504 : errmsg("unsafe use of pseudo-type \"internal\""),
505 : errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
506 :
507 : /*
508 : * If a moving-aggregate implementation is supplied, look up its finalfn
509 : * if any, and check that the implied aggregate result type matches the
510 : * plain implementation.
511 : */
512 71 : if (OidIsValid(aggmTransType))
513 : {
514 : /* handle finalfn, if supplied */
515 6 : if (aggmfinalfnName)
516 : {
517 : /*
518 : * The arguments are figured the same way as for the regular
519 : * finalfn, but using aggmTransType and mfinalfnExtraArgs.
520 : */
521 0 : Oid ffnVariadicArgType = variadicArgType;
522 :
523 0 : fnArgs[0] = aggmTransType;
524 0 : memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
525 0 : if (mfinalfnExtraArgs)
526 0 : nargs_finalfn = numArgs + 1;
527 : else
528 : {
529 0 : nargs_finalfn = numDirectArgs + 1;
530 0 : if (numDirectArgs < numArgs)
531 : {
532 : /* variadic argument doesn't affect finalfn */
533 0 : ffnVariadicArgType = InvalidOid;
534 : }
535 : }
536 :
537 0 : mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
538 : fnArgs, ffnVariadicArgType,
539 : &rettype);
540 :
541 : /* As above, check strictness if mfinalfnExtraArgs is given */
542 0 : if (mfinalfnExtraArgs && func_strict(mfinalfn))
543 0 : ereport(ERROR,
544 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
545 : errmsg("final function with extra arguments must not be declared STRICT")));
546 : }
547 : else
548 : {
549 : /*
550 : * If no finalfn, aggregate result type is type of the state value
551 : */
552 6 : rettype = aggmTransType;
553 : }
554 6 : Assert(OidIsValid(rettype));
555 6 : if (rettype != finaltype)
556 0 : ereport(ERROR,
557 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
558 : errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
559 : format_type_be(aggmTransType),
560 : format_type_be(aggTransType))));
561 : }
562 :
563 : /* handle sortop, if supplied */
564 71 : if (aggsortopName)
565 : {
566 0 : if (numArgs != 1)
567 0 : ereport(ERROR,
568 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
569 : errmsg("sort operator can only be specified for single-argument aggregates")));
570 0 : sortop = LookupOperName(NULL, aggsortopName,
571 : aggArgTypes[0], aggArgTypes[0],
572 : false, -1);
573 : }
574 :
575 : /*
576 : * permission checks on used types
577 : */
578 143 : for (i = 0; i < numArgs; i++)
579 : {
580 72 : aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
581 72 : if (aclresult != ACLCHECK_OK)
582 0 : aclcheck_error_type(aclresult, aggArgTypes[i]);
583 : }
584 :
585 71 : aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
586 71 : if (aclresult != ACLCHECK_OK)
587 0 : aclcheck_error_type(aclresult, aggTransType);
588 :
589 71 : if (OidIsValid(aggmTransType))
590 : {
591 6 : aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE);
592 6 : if (aclresult != ACLCHECK_OK)
593 0 : aclcheck_error_type(aclresult, aggmTransType);
594 : }
595 :
596 71 : aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
597 71 : if (aclresult != ACLCHECK_OK)
598 0 : aclcheck_error_type(aclresult, finaltype);
599 :
600 :
601 : /*
602 : * Everything looks okay. Try to create the pg_proc entry for the
603 : * aggregate. (This could fail if there's already a conflicting entry.)
604 : */
605 :
606 71 : myself = ProcedureCreate(aggName,
607 : aggNamespace,
608 : false, /* no replacement */
609 : false, /* doesn't return a set */
610 : finaltype, /* returnType */
611 : GetUserId(), /* proowner */
612 : INTERNALlanguageId, /* languageObjectId */
613 : InvalidOid, /* no validator */
614 : "aggregate_dummy", /* placeholder proc */
615 : NULL, /* probin */
616 : true, /* isAgg */
617 : false, /* isWindowFunc */
618 : false, /* security invoker (currently not
619 : * definable for agg) */
620 : false, /* isLeakProof */
621 : false, /* isStrict (not needed for agg) */
622 : PROVOLATILE_IMMUTABLE, /* volatility (not needed
623 : * for agg) */
624 : proparallel,
625 : parameterTypes, /* paramTypes */
626 : allParameterTypes, /* allParamTypes */
627 : parameterModes, /* parameterModes */
628 : parameterNames, /* parameterNames */
629 : parameterDefaults, /* parameterDefaults */
630 : PointerGetDatum(NULL), /* trftypes */
631 : PointerGetDatum(NULL), /* proconfig */
632 : 1, /* procost */
633 : 0); /* prorows */
634 70 : procOid = myself.objectId;
635 :
636 : /*
637 : * Okay to create the pg_aggregate entry.
638 : */
639 :
640 : /* initialize nulls and values */
641 1470 : for (i = 0; i < Natts_pg_aggregate; i++)
642 : {
643 1400 : nulls[i] = false;
644 1400 : values[i] = (Datum) NULL;
645 : }
646 70 : values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
647 70 : values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
648 70 : values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
649 70 : values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
650 70 : values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
651 70 : values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
652 70 : values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
653 70 : values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
654 70 : values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
655 70 : values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
656 70 : values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
657 70 : values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
658 70 : values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
659 70 : values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
660 70 : values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
661 70 : values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
662 70 : values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
663 70 : values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
664 70 : if (agginitval)
665 42 : values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
666 : else
667 28 : nulls[Anum_pg_aggregate_agginitval - 1] = true;
668 70 : if (aggminitval)
669 2 : values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
670 : else
671 68 : nulls[Anum_pg_aggregate_aggminitval - 1] = true;
672 :
673 70 : aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
674 70 : tupDesc = aggdesc->rd_att;
675 :
676 70 : tup = heap_form_tuple(tupDesc, values, nulls);
677 70 : CatalogTupleInsert(aggdesc, tup);
678 :
679 70 : heap_close(aggdesc, RowExclusiveLock);
680 :
681 : /*
682 : * Create dependencies for the aggregate (above and beyond those already
683 : * made by ProcedureCreate). Note: we don't need an explicit dependency
684 : * on aggTransType since we depend on it indirectly through transfn.
685 : * Likewise for aggmTransType using the mtransfunc, if it exists.
686 : */
687 :
688 : /* Depends on transition function */
689 70 : referenced.classId = ProcedureRelationId;
690 70 : referenced.objectId = transfn;
691 70 : referenced.objectSubId = 0;
692 70 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
693 :
694 : /* Depends on final function, if any */
695 70 : if (OidIsValid(finalfn))
696 : {
697 27 : referenced.classId = ProcedureRelationId;
698 27 : referenced.objectId = finalfn;
699 27 : referenced.objectSubId = 0;
700 27 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
701 : }
702 :
703 : /* Depends on combine function, if any */
704 70 : if (OidIsValid(combinefn))
705 : {
706 1 : referenced.classId = ProcedureRelationId;
707 1 : referenced.objectId = combinefn;
708 1 : referenced.objectSubId = 0;
709 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
710 : }
711 :
712 : /* Depends on serialization function, if any */
713 70 : if (OidIsValid(serialfn))
714 : {
715 1 : referenced.classId = ProcedureRelationId;
716 1 : referenced.objectId = serialfn;
717 1 : referenced.objectSubId = 0;
718 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
719 : }
720 :
721 : /* Depends on deserialization function, if any */
722 70 : if (OidIsValid(deserialfn))
723 : {
724 1 : referenced.classId = ProcedureRelationId;
725 1 : referenced.objectId = deserialfn;
726 1 : referenced.objectSubId = 0;
727 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
728 : }
729 :
730 : /* Depends on forward transition function, if any */
731 70 : if (OidIsValid(mtransfn))
732 : {
733 6 : referenced.classId = ProcedureRelationId;
734 6 : referenced.objectId = mtransfn;
735 6 : referenced.objectSubId = 0;
736 6 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
737 : }
738 :
739 : /* Depends on inverse transition function, if any */
740 70 : if (OidIsValid(minvtransfn))
741 : {
742 6 : referenced.classId = ProcedureRelationId;
743 6 : referenced.objectId = minvtransfn;
744 6 : referenced.objectSubId = 0;
745 6 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
746 : }
747 :
748 : /* Depends on final function, if any */
749 70 : if (OidIsValid(mfinalfn))
750 : {
751 0 : referenced.classId = ProcedureRelationId;
752 0 : referenced.objectId = mfinalfn;
753 0 : referenced.objectSubId = 0;
754 0 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
755 : }
756 :
757 : /* Depends on sort operator, if any */
758 70 : if (OidIsValid(sortop))
759 : {
760 0 : referenced.classId = OperatorRelationId;
761 0 : referenced.objectId = sortop;
762 0 : referenced.objectSubId = 0;
763 0 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
764 : }
765 :
766 70 : return myself;
767 : }
768 :
769 : /*
770 : * lookup_agg_function
771 : * common code for finding transfn, invtransfn, finalfn, and combinefn
772 : *
773 : * Returns OID of function, and stores its return type into *rettype
774 : *
775 : * NB: must not scribble on input_types[], as we may re-use those
776 : */
777 : static Oid
778 149 : lookup_agg_function(List *fnName,
779 : int nargs,
780 : Oid *input_types,
781 : Oid variadicArgType,
782 : Oid *rettype)
783 : {
784 : Oid fnOid;
785 : bool retset;
786 : int nvargs;
787 : Oid vatype;
788 : Oid *true_oid_array;
789 : FuncDetailCode fdresult;
790 : AclResult aclresult;
791 : int i;
792 :
793 : /*
794 : * func_get_detail looks up the function in the catalogs, does
795 : * disambiguation for polymorphic functions, handles inheritance, and
796 : * returns the funcid and type and set or singleton status of the
797 : * function's return value. it also returns the true argument types to
798 : * the function.
799 : */
800 149 : fdresult = func_get_detail(fnName, NIL, NIL,
801 : nargs, input_types, false, false,
802 : &fnOid, rettype, &retset,
803 : &nvargs, &vatype,
804 : &true_oid_array, NULL);
805 :
806 : /* only valid case is a normal function not returning a set */
807 149 : if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
808 24 : ereport(ERROR,
809 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
810 : errmsg("function %s does not exist",
811 : func_signature_string(fnName, nargs,
812 : NIL, input_types))));
813 125 : if (retset)
814 0 : ereport(ERROR,
815 : (errcode(ERRCODE_DATATYPE_MISMATCH),
816 : errmsg("function %s returns a set",
817 : func_signature_string(fnName, nargs,
818 : NIL, input_types))));
819 :
820 : /*
821 : * If the agg is declared to take VARIADIC ANY, the underlying functions
822 : * had better be declared that way too, else they may receive too many
823 : * parameters; but func_get_detail would have been happy with plain ANY.
824 : * (Probably nothing very bad would happen, but it wouldn't work as the
825 : * user expects.) Other combinations should work without any special
826 : * pushups, given that we told func_get_detail not to expand VARIADIC.
827 : */
828 125 : if (variadicArgType == ANYOID && vatype != ANYOID)
829 0 : ereport(ERROR,
830 : (errcode(ERRCODE_DATATYPE_MISMATCH),
831 : errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
832 : func_signature_string(fnName, nargs,
833 : NIL, input_types))));
834 :
835 : /*
836 : * If there are any polymorphic types involved, enforce consistency, and
837 : * possibly refine the result type. It's OK if the result is still
838 : * polymorphic at this point, though.
839 : */
840 125 : *rettype = enforce_generic_type_consistency(input_types,
841 : true_oid_array,
842 : nargs,
843 : *rettype,
844 : true);
845 :
846 : /*
847 : * func_get_detail will find functions requiring run-time argument type
848 : * coercion, but nodeAgg.c isn't prepared to deal with that
849 : */
850 349 : for (i = 0; i < nargs; i++)
851 : {
852 224 : if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
853 0 : ereport(ERROR,
854 : (errcode(ERRCODE_DATATYPE_MISMATCH),
855 : errmsg("function %s requires run-time type coercion",
856 : func_signature_string(fnName, nargs,
857 : NIL, true_oid_array))));
858 : }
859 :
860 : /* Check aggregate creator has permission to call the function */
861 125 : aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
862 125 : if (aclresult != ACLCHECK_OK)
863 0 : aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(fnOid));
864 :
865 125 : return fnOid;
866 : }
|