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