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