Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * functioncmds.c
4 : *
5 : * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
6 : * CAST commands.
7 : *
8 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 : * Portions Copyright (c) 1994, Regents of the University of California
10 : *
11 : *
12 : * IDENTIFICATION
13 : * src/backend/commands/functioncmds.c
14 : *
15 : * DESCRIPTION
16 : * These routines take the parse tree and pick out the
17 : * appropriate arguments/flags, and pass the results to the
18 : * corresponding "FooCreate" routines (in src/backend/catalog) that do
19 : * the actual catalog-munging. These routines also verify permission
20 : * of the user to execute the command.
21 : *
22 : * NOTES
23 : * These things must be defined and committed in the following order:
24 : * "create function":
25 : * input/output, recv/send procedures
26 : * "create type":
27 : * type
28 : * "create operator":
29 : * operators
30 : *
31 : *-------------------------------------------------------------------------
32 : */
33 : #include "postgres.h"
34 :
35 : #include "access/htup_details.h"
36 : #include "access/table.h"
37 : #include "catalog/catalog.h"
38 : #include "catalog/dependency.h"
39 : #include "catalog/indexing.h"
40 : #include "catalog/objectaccess.h"
41 : #include "catalog/pg_aggregate.h"
42 : #include "catalog/pg_cast.h"
43 : #include "catalog/pg_language.h"
44 : #include "catalog/pg_namespace.h"
45 : #include "catalog/pg_proc.h"
46 : #include "catalog/pg_transform.h"
47 : #include "catalog/pg_type.h"
48 : #include "commands/defrem.h"
49 : #include "commands/extension.h"
50 : #include "commands/proclang.h"
51 : #include "executor/executor.h"
52 : #include "executor/functions.h"
53 : #include "funcapi.h"
54 : #include "miscadmin.h"
55 : #include "nodes/nodeFuncs.h"
56 : #include "optimizer/optimizer.h"
57 : #include "parser/analyze.h"
58 : #include "parser/parse_coerce.h"
59 : #include "parser/parse_collate.h"
60 : #include "parser/parse_expr.h"
61 : #include "parser/parse_func.h"
62 : #include "parser/parse_type.h"
63 : #include "pgstat.h"
64 : #include "tcop/pquery.h"
65 : #include "tcop/utility.h"
66 : #include "utils/acl.h"
67 : #include "utils/builtins.h"
68 : #include "utils/guc.h"
69 : #include "utils/lsyscache.h"
70 : #include "utils/rel.h"
71 : #include "utils/snapmgr.h"
72 : #include "utils/syscache.h"
73 : #include "utils/typcache.h"
74 :
75 : /*
76 : * Examine the RETURNS clause of the CREATE FUNCTION statement
77 : * and return information about it as *prorettype_p and *returnsSet_p.
78 : *
79 : * This is more complex than the average typename lookup because we want to
80 : * allow a shell type to be used, or even created if the specified return type
81 : * doesn't exist yet. (Without this, there's no way to define the I/O procs
82 : * for a new type.) But SQL function creation won't cope, so error out if
83 : * the target language is SQL. (We do this here, not in the SQL-function
84 : * validator, so as not to produce a NOTICE and then an ERROR for the same
85 : * condition.)
86 : */
87 : static void
88 21518 : compute_return_type(TypeName *returnType, Oid languageOid,
89 : Oid *prorettype_p, bool *returnsSet_p)
90 : {
91 : Oid rettype;
92 : Type typtup;
93 : AclResult aclresult;
94 :
95 21518 : typtup = LookupTypeName(NULL, returnType, NULL, false);
96 :
97 21518 : if (typtup)
98 : {
99 21444 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
100 : {
101 154 : if (languageOid == SQLlanguageId)
102 0 : ereport(ERROR,
103 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
104 : errmsg("SQL function cannot return shell type %s",
105 : TypeNameToString(returnType))));
106 : else
107 154 : ereport(NOTICE,
108 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
109 : errmsg("return type %s is only a shell",
110 : TypeNameToString(returnType))));
111 : }
112 21444 : rettype = typeTypeId(typtup);
113 21444 : ReleaseSysCache(typtup);
114 : }
115 : else
116 : {
117 74 : char *typnam = TypeNameToString(returnType);
118 : Oid namespaceId;
119 : char *typname;
120 : ObjectAddress address;
121 :
122 : /*
123 : * Only C-coded functions can be I/O functions. We enforce this
124 : * restriction here mainly to prevent littering the catalogs with
125 : * shell types due to simple typos in user-defined function
126 : * definitions.
127 : */
128 74 : if (languageOid != INTERNALlanguageId &&
129 : languageOid != ClanguageId)
130 0 : ereport(ERROR,
131 : (errcode(ERRCODE_UNDEFINED_OBJECT),
132 : errmsg("type \"%s\" does not exist", typnam)));
133 :
134 : /* Reject if there's typmod decoration, too */
135 74 : if (returnType->typmods != NIL)
136 0 : ereport(ERROR,
137 : (errcode(ERRCODE_SYNTAX_ERROR),
138 : errmsg("type modifier cannot be specified for shell type \"%s\"",
139 : typnam)));
140 :
141 : /* Otherwise, go ahead and make a shell type */
142 74 : ereport(NOTICE,
143 : (errcode(ERRCODE_UNDEFINED_OBJECT),
144 : errmsg("type \"%s\" is not yet defined", typnam),
145 : errdetail("Creating a shell type definition.")));
146 74 : namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
147 : &typname);
148 74 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(),
149 : ACL_CREATE);
150 74 : if (aclresult != ACLCHECK_OK)
151 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
152 0 : get_namespace_name(namespaceId));
153 74 : address = TypeShellMake(typname, namespaceId, GetUserId());
154 74 : rettype = address.objectId;
155 : Assert(OidIsValid(rettype));
156 : }
157 :
158 21518 : aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
159 21518 : if (aclresult != ACLCHECK_OK)
160 6 : aclcheck_error_type(aclresult, rettype);
161 :
162 21512 : *prorettype_p = rettype;
163 21512 : *returnsSet_p = returnType->setof;
164 21512 : }
165 :
166 : /*
167 : * Interpret the function parameter list of a CREATE FUNCTION,
168 : * CREATE PROCEDURE, or CREATE AGGREGATE statement.
169 : *
170 : * Input parameters:
171 : * parameters: list of FunctionParameter structs
172 : * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE)
173 : * objtype: identifies type of object being created
174 : *
175 : * Results are stored into output parameters. parameterTypes must always
176 : * be created, but the other arrays/lists can be NULL pointers if not needed.
177 : * variadicArgType is set to the variadic array type if there's a VARIADIC
178 : * parameter (there can be only one); or to InvalidOid if not.
179 : * requiredResultType is set to InvalidOid if there are no OUT parameters,
180 : * else it is set to the OID of the implied result type.
181 : */
182 : void
183 22924 : interpret_function_parameter_list(ParseState *pstate,
184 : List *parameters,
185 : Oid languageOid,
186 : ObjectType objtype,
187 : oidvector **parameterTypes,
188 : List **parameterTypes_list,
189 : ArrayType **allParameterTypes,
190 : ArrayType **parameterModes,
191 : ArrayType **parameterNames,
192 : List **inParameterNames_list,
193 : List **parameterDefaults,
194 : Oid *variadicArgType,
195 : Oid *requiredResultType)
196 : {
197 22924 : int parameterCount = list_length(parameters);
198 : Oid *inTypes;
199 22924 : int inCount = 0;
200 : Datum *allTypes;
201 : Datum *paramModes;
202 : Datum *paramNames;
203 22924 : int outCount = 0;
204 22924 : int varCount = 0;
205 22924 : bool have_names = false;
206 22924 : bool have_defaults = false;
207 : ListCell *x;
208 : int i;
209 :
210 22924 : *variadicArgType = InvalidOid; /* default result */
211 22924 : *requiredResultType = InvalidOid; /* default result */
212 :
213 22924 : inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
214 22924 : allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
215 22924 : paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
216 22924 : paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
217 22924 : *parameterDefaults = NIL;
218 :
219 : /* Scan the list and extract data into work arrays */
220 22924 : i = 0;
221 73882 : foreach(x, parameters)
222 : {
223 51018 : FunctionParameter *fp = (FunctionParameter *) lfirst(x);
224 51018 : TypeName *t = fp->argType;
225 51018 : FunctionParameterMode fpmode = fp->mode;
226 51018 : bool isinput = false;
227 : Oid toid;
228 : Type typtup;
229 : AclResult aclresult;
230 :
231 : /* For our purposes here, a defaulted mode spec is identical to IN */
232 51018 : if (fpmode == FUNC_PARAM_DEFAULT)
233 35702 : fpmode = FUNC_PARAM_IN;
234 :
235 51018 : typtup = LookupTypeName(pstate, t, NULL, false);
236 51018 : if (typtup)
237 : {
238 51018 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
239 : {
240 : /* As above, hard error if language is SQL */
241 222 : if (languageOid == SQLlanguageId)
242 0 : ereport(ERROR,
243 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
244 : errmsg("SQL function cannot accept shell type %s",
245 : TypeNameToString(t)),
246 : parser_errposition(pstate, t->location)));
247 : /* We don't allow creating aggregates on shell types either */
248 222 : else if (objtype == OBJECT_AGGREGATE)
249 0 : ereport(ERROR,
250 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
251 : errmsg("aggregate cannot accept shell type %s",
252 : TypeNameToString(t)),
253 : parser_errposition(pstate, t->location)));
254 : else
255 222 : ereport(NOTICE,
256 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
257 : errmsg("argument type %s is only a shell",
258 : TypeNameToString(t)),
259 : parser_errposition(pstate, t->location)));
260 : }
261 51018 : toid = typeTypeId(typtup);
262 51018 : ReleaseSysCache(typtup);
263 : }
264 : else
265 : {
266 0 : ereport(ERROR,
267 : (errcode(ERRCODE_UNDEFINED_OBJECT),
268 : errmsg("type %s does not exist",
269 : TypeNameToString(t)),
270 : parser_errposition(pstate, t->location)));
271 : toid = InvalidOid; /* keep compiler quiet */
272 : }
273 :
274 51018 : aclresult = object_aclcheck(TypeRelationId, toid, GetUserId(), ACL_USAGE);
275 51018 : if (aclresult != ACLCHECK_OK)
276 12 : aclcheck_error_type(aclresult, toid);
277 :
278 51006 : if (t->setof)
279 : {
280 0 : if (objtype == OBJECT_AGGREGATE)
281 0 : ereport(ERROR,
282 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
283 : errmsg("aggregates cannot accept set arguments"),
284 : parser_errposition(pstate, fp->location)));
285 0 : else if (objtype == OBJECT_PROCEDURE)
286 0 : ereport(ERROR,
287 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
288 : errmsg("procedures cannot accept set arguments"),
289 : parser_errposition(pstate, fp->location)));
290 : else
291 0 : ereport(ERROR,
292 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
293 : errmsg("functions cannot accept set arguments"),
294 : parser_errposition(pstate, fp->location)));
295 : }
296 :
297 : /* handle input parameters */
298 51006 : if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
299 : {
300 : /* other input parameters can't follow a VARIADIC parameter */
301 39650 : if (varCount > 0)
302 0 : ereport(ERROR,
303 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
304 : errmsg("VARIADIC parameter must be the last input parameter"),
305 : parser_errposition(pstate, fp->location)));
306 39650 : inTypes[inCount++] = toid;
307 39650 : isinput = true;
308 39650 : if (parameterTypes_list)
309 39122 : *parameterTypes_list = lappend_oid(*parameterTypes_list, toid);
310 : }
311 :
312 : /* handle output parameters */
313 51006 : if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
314 : {
315 11538 : if (objtype == OBJECT_PROCEDURE)
316 : {
317 : /*
318 : * We disallow OUT-after-VARIADIC only for procedures. While
319 : * such a case causes no confusion in ordinary function calls,
320 : * it would cause confusion in a CALL statement.
321 : */
322 190 : if (varCount > 0)
323 6 : ereport(ERROR,
324 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
325 : errmsg("VARIADIC parameter must be the last parameter"),
326 : parser_errposition(pstate, fp->location)));
327 : /* Procedures with output parameters always return RECORD */
328 184 : *requiredResultType = RECORDOID;
329 : }
330 11348 : else if (outCount == 0) /* save first output param's type */
331 2246 : *requiredResultType = toid;
332 11532 : outCount++;
333 : }
334 :
335 51000 : if (fpmode == FUNC_PARAM_VARIADIC)
336 : {
337 460 : *variadicArgType = toid;
338 460 : varCount++;
339 : /* validate variadic parameter type */
340 460 : switch (toid)
341 : {
342 70 : case ANYARRAYOID:
343 : case ANYCOMPATIBLEARRAYOID:
344 : case ANYOID:
345 : /* okay */
346 70 : break;
347 390 : default:
348 390 : if (!OidIsValid(get_element_type(toid)))
349 0 : ereport(ERROR,
350 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
351 : errmsg("VARIADIC parameter must be an array"),
352 : parser_errposition(pstate, fp->location)));
353 390 : break;
354 : }
355 50540 : }
356 :
357 51000 : allTypes[i] = ObjectIdGetDatum(toid);
358 :
359 51000 : paramModes[i] = CharGetDatum(fpmode);
360 :
361 51000 : if (fp->name && fp->name[0])
362 : {
363 : ListCell *px;
364 :
365 : /*
366 : * As of Postgres 9.0 we disallow using the same name for two
367 : * input or two output function parameters. Depending on the
368 : * function's language, conflicting input and output names might
369 : * be bad too, but we leave it to the PL to complain if so.
370 : */
371 151782 : foreach(px, parameters)
372 : {
373 151782 : FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
374 : FunctionParameterMode prevfpmode;
375 :
376 151782 : if (prevfp == fp)
377 30050 : break;
378 : /* as above, default mode is IN */
379 121732 : prevfpmode = prevfp->mode;
380 121732 : if (prevfpmode == FUNC_PARAM_DEFAULT)
381 29918 : prevfpmode = FUNC_PARAM_IN;
382 : /* pure in doesn't conflict with pure out */
383 121732 : if ((fpmode == FUNC_PARAM_IN ||
384 29718 : fpmode == FUNC_PARAM_VARIADIC) &&
385 29660 : (prevfpmode == FUNC_PARAM_OUT ||
386 : prevfpmode == FUNC_PARAM_TABLE))
387 58 : continue;
388 121674 : if ((prevfpmode == FUNC_PARAM_IN ||
389 49038 : prevfpmode == FUNC_PARAM_VARIADIC) &&
390 30138 : (fpmode == FUNC_PARAM_OUT ||
391 : fpmode == FUNC_PARAM_TABLE))
392 19334 : continue;
393 102340 : if (prevfp->name && prevfp->name[0] &&
394 102310 : strcmp(prevfp->name, fp->name) == 0)
395 24 : ereport(ERROR,
396 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
397 : errmsg("parameter name \"%s\" used more than once",
398 : fp->name),
399 : parser_errposition(pstate, fp->location)));
400 : }
401 :
402 30050 : paramNames[i] = CStringGetTextDatum(fp->name);
403 30050 : have_names = true;
404 : }
405 :
406 50976 : if (inParameterNames_list)
407 50448 : *inParameterNames_list = lappend(*inParameterNames_list, makeString(fp->name ? fp->name : pstrdup("")));
408 :
409 50976 : if (fp->defexpr)
410 : {
411 : Node *def;
412 :
413 6830 : if (!isinput)
414 6 : ereport(ERROR,
415 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
416 : errmsg("only input parameters can have default values"),
417 : parser_errposition(pstate, fp->location)));
418 :
419 6824 : def = transformExpr(pstate, fp->defexpr,
420 : EXPR_KIND_FUNCTION_DEFAULT);
421 6824 : def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
422 6824 : assign_expr_collations(pstate, def);
423 :
424 : /*
425 : * Make sure no variables are referred to (this is probably dead
426 : * code now that add_missing_from is history).
427 : */
428 13648 : if (pstate->p_rtable != NIL ||
429 6824 : contain_var_clause(def))
430 0 : ereport(ERROR,
431 : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
432 : errmsg("cannot use table references in parameter default value"),
433 : parser_errposition(pstate, fp->location)));
434 :
435 : /*
436 : * transformExpr() should have already rejected subqueries,
437 : * aggregates, and window functions, based on the EXPR_KIND_ for a
438 : * default expression.
439 : *
440 : * It can't return a set either --- but coerce_to_specific_type
441 : * already checked that for us.
442 : *
443 : * Note: the point of these restrictions is to ensure that an
444 : * expression that, on its face, hasn't got subplans, aggregates,
445 : * etc cannot suddenly have them after function default arguments
446 : * are inserted.
447 : */
448 :
449 6824 : *parameterDefaults = lappend(*parameterDefaults, def);
450 6824 : have_defaults = true;
451 : }
452 : else
453 : {
454 44146 : if (isinput && have_defaults)
455 6 : ereport(ERROR,
456 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
457 : errmsg("input parameters after one with a default value must also have defaults"),
458 : parser_errposition(pstate, fp->location)));
459 :
460 : /*
461 : * For procedures, we also can't allow OUT parameters after one
462 : * with a default, because the same sort of confusion arises in a
463 : * CALL statement.
464 : */
465 44140 : if (objtype == OBJECT_PROCEDURE && have_defaults)
466 6 : ereport(ERROR,
467 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
468 : errmsg("procedure OUT parameters cannot appear after one with a default value"),
469 : parser_errposition(pstate, fp->location)));
470 : }
471 :
472 50958 : i++;
473 : }
474 :
475 : /* Now construct the proper outputs as needed */
476 22864 : *parameterTypes = buildoidvector(inTypes, inCount);
477 :
478 22864 : if (outCount > 0 || varCount > 0)
479 : {
480 2438 : *allParameterTypes = construct_array_builtin(allTypes, parameterCount, OIDOID);
481 2438 : *parameterModes = construct_array_builtin(paramModes, parameterCount, CHAROID);
482 2438 : if (outCount > 1)
483 2100 : *requiredResultType = RECORDOID;
484 : /* otherwise we set requiredResultType correctly above */
485 : }
486 : else
487 : {
488 20426 : *allParameterTypes = NULL;
489 20426 : *parameterModes = NULL;
490 : }
491 :
492 22864 : if (have_names)
493 : {
494 37820 : for (i = 0; i < parameterCount; i++)
495 : {
496 30236 : if (paramNames[i] == PointerGetDatum(NULL))
497 240 : paramNames[i] = CStringGetTextDatum("");
498 : }
499 7584 : *parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
500 : }
501 : else
502 15280 : *parameterNames = NULL;
503 22864 : }
504 :
505 :
506 : /*
507 : * Recognize one of the options that can be passed to both CREATE
508 : * FUNCTION and ALTER FUNCTION and return it via one of the out
509 : * parameters. Returns true if the passed option was recognized. If
510 : * the out parameter we were going to assign to points to non-NULL,
511 : * raise a duplicate-clause error. (We don't try to detect duplicate
512 : * SET parameters though --- if you're redundant, the last one wins.)
513 : */
514 : static bool
515 41550 : compute_common_attribute(ParseState *pstate,
516 : bool is_procedure,
517 : DefElem *defel,
518 : DefElem **volatility_item,
519 : DefElem **strict_item,
520 : DefElem **security_item,
521 : DefElem **leakproof_item,
522 : List **set_items,
523 : DefElem **cost_item,
524 : DefElem **rows_item,
525 : DefElem **support_item,
526 : DefElem **parallel_item)
527 : {
528 41550 : if (strcmp(defel->defname, "volatility") == 0)
529 : {
530 12330 : if (is_procedure)
531 0 : goto procedure_error;
532 12330 : if (*volatility_item)
533 0 : errorConflictingDefElem(defel, pstate);
534 :
535 12330 : *volatility_item = defel;
536 : }
537 29220 : else if (strcmp(defel->defname, "strict") == 0)
538 : {
539 12544 : if (is_procedure)
540 12 : goto procedure_error;
541 12532 : if (*strict_item)
542 0 : errorConflictingDefElem(defel, pstate);
543 :
544 12532 : *strict_item = defel;
545 : }
546 16676 : else if (strcmp(defel->defname, "security") == 0)
547 : {
548 60 : if (*security_item)
549 0 : errorConflictingDefElem(defel, pstate);
550 :
551 60 : *security_item = defel;
552 : }
553 16616 : else if (strcmp(defel->defname, "leakproof") == 0)
554 : {
555 58 : if (is_procedure)
556 0 : goto procedure_error;
557 58 : if (*leakproof_item)
558 0 : errorConflictingDefElem(defel, pstate);
559 :
560 58 : *leakproof_item = defel;
561 : }
562 16558 : else if (strcmp(defel->defname, "set") == 0)
563 : {
564 140 : *set_items = lappend(*set_items, defel->arg);
565 : }
566 16418 : else if (strcmp(defel->defname, "cost") == 0)
567 : {
568 3908 : if (is_procedure)
569 0 : goto procedure_error;
570 3908 : if (*cost_item)
571 0 : errorConflictingDefElem(defel, pstate);
572 :
573 3908 : *cost_item = defel;
574 : }
575 12510 : else if (strcmp(defel->defname, "rows") == 0)
576 : {
577 540 : if (is_procedure)
578 0 : goto procedure_error;
579 540 : if (*rows_item)
580 0 : errorConflictingDefElem(defel, pstate);
581 :
582 540 : *rows_item = defel;
583 : }
584 11970 : else if (strcmp(defel->defname, "support") == 0)
585 : {
586 104 : if (is_procedure)
587 0 : goto procedure_error;
588 104 : if (*support_item)
589 0 : errorConflictingDefElem(defel, pstate);
590 :
591 104 : *support_item = defel;
592 : }
593 11866 : else if (strcmp(defel->defname, "parallel") == 0)
594 : {
595 11866 : if (is_procedure)
596 0 : goto procedure_error;
597 11866 : if (*parallel_item)
598 0 : errorConflictingDefElem(defel, pstate);
599 :
600 11866 : *parallel_item = defel;
601 : }
602 : else
603 0 : return false;
604 :
605 : /* Recognized an option */
606 41538 : return true;
607 :
608 12 : procedure_error:
609 12 : ereport(ERROR,
610 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
611 : errmsg("invalid attribute in procedure definition"),
612 : parser_errposition(pstate, defel->location)));
613 : return false;
614 : }
615 :
616 : static char
617 12330 : interpret_func_volatility(DefElem *defel)
618 : {
619 12330 : char *str = strVal(defel->arg);
620 :
621 12330 : if (strcmp(str, "immutable") == 0)
622 8576 : return PROVOLATILE_IMMUTABLE;
623 3754 : else if (strcmp(str, "stable") == 0)
624 2100 : return PROVOLATILE_STABLE;
625 1654 : else if (strcmp(str, "volatile") == 0)
626 1654 : return PROVOLATILE_VOLATILE;
627 : else
628 : {
629 0 : elog(ERROR, "invalid volatility \"%s\"", str);
630 : return 0; /* keep compiler quiet */
631 : }
632 : }
633 :
634 : static char
635 11866 : interpret_func_parallel(DefElem *defel)
636 : {
637 11866 : char *str = strVal(defel->arg);
638 :
639 11866 : if (strcmp(str, "safe") == 0)
640 10696 : return PROPARALLEL_SAFE;
641 1170 : else if (strcmp(str, "unsafe") == 0)
642 318 : return PROPARALLEL_UNSAFE;
643 852 : else if (strcmp(str, "restricted") == 0)
644 852 : return PROPARALLEL_RESTRICTED;
645 : else
646 : {
647 0 : ereport(ERROR,
648 : (errcode(ERRCODE_SYNTAX_ERROR),
649 : errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
650 : return PROPARALLEL_UNSAFE; /* keep compiler quiet */
651 : }
652 : }
653 :
654 : /*
655 : * Update a proconfig value according to a list of VariableSetStmt items.
656 : *
657 : * The input and result may be NULL to signify a null entry.
658 : */
659 : static ArrayType *
660 108 : update_proconfig_value(ArrayType *a, List *set_items)
661 : {
662 : ListCell *l;
663 :
664 248 : foreach(l, set_items)
665 : {
666 140 : VariableSetStmt *sstmt = lfirst_node(VariableSetStmt, l);
667 :
668 140 : if (sstmt->kind == VAR_RESET_ALL)
669 12 : a = NULL;
670 : else
671 : {
672 128 : char *valuestr = ExtractSetVariableArgs(sstmt);
673 :
674 128 : if (valuestr)
675 128 : a = GUCArrayAdd(a, sstmt->name, valuestr);
676 : else /* RESET */
677 0 : a = GUCArrayDelete(a, sstmt->name);
678 : }
679 : }
680 :
681 108 : return a;
682 : }
683 :
684 : static Oid
685 104 : interpret_func_support(DefElem *defel)
686 : {
687 104 : List *procName = defGetQualifiedName(defel);
688 : Oid procOid;
689 : Oid argList[1];
690 :
691 : /*
692 : * Support functions always take one INTERNAL argument and return
693 : * INTERNAL.
694 : */
695 104 : argList[0] = INTERNALOID;
696 :
697 104 : procOid = LookupFuncName(procName, 1, argList, true);
698 104 : if (!OidIsValid(procOid))
699 0 : ereport(ERROR,
700 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
701 : errmsg("function %s does not exist",
702 : func_signature_string(procName, 1, NIL, argList))));
703 :
704 104 : if (get_func_rettype(procOid) != INTERNALOID)
705 0 : ereport(ERROR,
706 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
707 : errmsg("support function %s must return type %s",
708 : NameListToString(procName), "internal")));
709 :
710 : /*
711 : * Someday we might want an ACL check here; but for now, we insist that
712 : * you be superuser to specify a support function, so privilege on the
713 : * support function is moot.
714 : */
715 104 : if (!superuser())
716 0 : ereport(ERROR,
717 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
718 : errmsg("must be superuser to specify a support function")));
719 :
720 104 : return procOid;
721 : }
722 :
723 :
724 : /*
725 : * Dissect the list of options assembled in gram.y into function
726 : * attributes.
727 : */
728 : static void
729 22412 : compute_function_attributes(ParseState *pstate,
730 : bool is_procedure,
731 : List *options,
732 : List **as,
733 : char **language,
734 : Node **transform,
735 : bool *windowfunc_p,
736 : char *volatility_p,
737 : bool *strict_p,
738 : bool *security_definer,
739 : bool *leakproof_p,
740 : ArrayType **proconfig,
741 : float4 *procost,
742 : float4 *prorows,
743 : Oid *prosupport,
744 : char *parallel_p)
745 : {
746 : ListCell *option;
747 22412 : DefElem *as_item = NULL;
748 22412 : DefElem *language_item = NULL;
749 22412 : DefElem *transform_item = NULL;
750 22412 : DefElem *windowfunc_item = NULL;
751 22412 : DefElem *volatility_item = NULL;
752 22412 : DefElem *strict_item = NULL;
753 22412 : DefElem *security_item = NULL;
754 22412 : DefElem *leakproof_item = NULL;
755 22412 : List *set_items = NIL;
756 22412 : DefElem *cost_item = NULL;
757 22412 : DefElem *rows_item = NULL;
758 22412 : DefElem *support_item = NULL;
759 22412 : DefElem *parallel_item = NULL;
760 :
761 103094 : foreach(option, options)
762 : {
763 80694 : DefElem *defel = (DefElem *) lfirst(option);
764 :
765 80694 : if (strcmp(defel->defname, "as") == 0)
766 : {
767 17296 : if (as_item)
768 0 : errorConflictingDefElem(defel, pstate);
769 17296 : as_item = defel;
770 : }
771 63398 : else if (strcmp(defel->defname, "language") == 0)
772 : {
773 22348 : if (language_item)
774 0 : errorConflictingDefElem(defel, pstate);
775 22348 : language_item = defel;
776 : }
777 41050 : else if (strcmp(defel->defname, "transform") == 0)
778 : {
779 118 : if (transform_item)
780 0 : errorConflictingDefElem(defel, pstate);
781 118 : transform_item = defel;
782 : }
783 40932 : else if (strcmp(defel->defname, "window") == 0)
784 : {
785 20 : if (windowfunc_item)
786 0 : errorConflictingDefElem(defel, pstate);
787 20 : if (is_procedure)
788 6 : ereport(ERROR,
789 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
790 : errmsg("invalid attribute in procedure definition"),
791 : parser_errposition(pstate, defel->location)));
792 14 : windowfunc_item = defel;
793 : }
794 40912 : else if (compute_common_attribute(pstate,
795 : is_procedure,
796 : defel,
797 : &volatility_item,
798 : &strict_item,
799 : &security_item,
800 : &leakproof_item,
801 : &set_items,
802 : &cost_item,
803 : &rows_item,
804 : &support_item,
805 : ¶llel_item))
806 : {
807 : /* recognized common option */
808 40906 : continue;
809 : }
810 : else
811 0 : elog(ERROR, "option \"%s\" not recognized",
812 : defel->defname);
813 : }
814 :
815 22400 : if (as_item)
816 17296 : *as = (List *) as_item->arg;
817 22400 : if (language_item)
818 22336 : *language = strVal(language_item->arg);
819 22400 : if (transform_item)
820 118 : *transform = transform_item->arg;
821 22400 : if (windowfunc_item)
822 14 : *windowfunc_p = boolVal(windowfunc_item->arg);
823 22400 : if (volatility_item)
824 12296 : *volatility_p = interpret_func_volatility(volatility_item);
825 22400 : if (strict_item)
826 12508 : *strict_p = boolVal(strict_item->arg);
827 22400 : if (security_item)
828 48 : *security_definer = boolVal(security_item->arg);
829 22400 : if (leakproof_item)
830 34 : *leakproof_p = boolVal(leakproof_item->arg);
831 22400 : if (set_items)
832 90 : *proconfig = update_proconfig_value(NULL, set_items);
833 22400 : if (cost_item)
834 : {
835 3896 : *procost = defGetNumeric(cost_item);
836 3896 : if (*procost <= 0)
837 0 : ereport(ERROR,
838 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
839 : errmsg("COST must be positive")));
840 : }
841 22400 : if (rows_item)
842 : {
843 540 : *prorows = defGetNumeric(rows_item);
844 540 : if (*prorows <= 0)
845 0 : ereport(ERROR,
846 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
847 : errmsg("ROWS must be positive")));
848 : }
849 22400 : if (support_item)
850 98 : *prosupport = interpret_func_support(support_item);
851 22400 : if (parallel_item)
852 11364 : *parallel_p = interpret_func_parallel(parallel_item);
853 22400 : }
854 :
855 :
856 : /*
857 : * For a dynamically linked C language object, the form of the clause is
858 : *
859 : * AS <object file name> [, <link symbol name> ]
860 : *
861 : * In all other cases
862 : *
863 : * AS <object reference, or sql code>
864 : */
865 : static void
866 22314 : interpret_AS_clause(Oid languageOid, const char *languageName,
867 : char *funcname, List *as, Node *sql_body_in,
868 : List *parameterTypes, List *inParameterNames,
869 : char **prosrc_str_p, char **probin_str_p,
870 : Node **sql_body_out,
871 : const char *queryString)
872 : {
873 22314 : if (!sql_body_in && !as)
874 0 : ereport(ERROR,
875 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
876 : errmsg("no function body specified")));
877 :
878 22314 : if (sql_body_in && as)
879 6 : ereport(ERROR,
880 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
881 : errmsg("duplicate function body specified")));
882 :
883 22308 : if (sql_body_in && languageOid != SQLlanguageId)
884 0 : ereport(ERROR,
885 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
886 : errmsg("inline SQL function body only valid for language SQL")));
887 :
888 22308 : *sql_body_out = NULL;
889 :
890 22308 : if (languageOid == ClanguageId)
891 : {
892 : /*
893 : * For "C" language, store the file name in probin and, when given,
894 : * the link symbol name in prosrc. If link symbol is omitted,
895 : * substitute procedure name. We also allow link symbol to be
896 : * specified as "-", since that was the habit in PG versions before
897 : * 8.4, and there might be dump files out there that don't translate
898 : * that back to "omitted".
899 : */
900 5042 : *probin_str_p = strVal(linitial(as));
901 5042 : if (list_length(as) == 1)
902 2328 : *prosrc_str_p = funcname;
903 : else
904 : {
905 2714 : *prosrc_str_p = strVal(lsecond(as));
906 2714 : if (strcmp(*prosrc_str_p, "-") == 0)
907 0 : *prosrc_str_p = funcname;
908 : }
909 : }
910 17266 : else if (sql_body_in)
911 : {
912 : SQLFunctionParseInfoPtr pinfo;
913 :
914 5104 : pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
915 :
916 5104 : pinfo->fname = funcname;
917 5104 : pinfo->nargs = list_length(parameterTypes);
918 5104 : pinfo->argtypes = (Oid *) palloc(pinfo->nargs * sizeof(Oid));
919 5104 : pinfo->argnames = (char **) palloc(pinfo->nargs * sizeof(char *));
920 15434 : for (int i = 0; i < list_length(parameterTypes); i++)
921 : {
922 10336 : char *s = strVal(list_nth(inParameterNames, i));
923 :
924 10336 : pinfo->argtypes[i] = list_nth_oid(parameterTypes, i);
925 10336 : if (IsPolymorphicType(pinfo->argtypes[i]))
926 6 : ereport(ERROR,
927 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
928 : errmsg("SQL function with unquoted function body cannot have polymorphic arguments")));
929 :
930 10330 : if (s[0] != '\0')
931 1716 : pinfo->argnames[i] = s;
932 : else
933 8614 : pinfo->argnames[i] = NULL;
934 : }
935 :
936 5098 : if (IsA(sql_body_in, List))
937 : {
938 728 : List *stmts = linitial_node(List, castNode(List, sql_body_in));
939 : ListCell *lc;
940 728 : List *transformed_stmts = NIL;
941 :
942 1448 : foreach(lc, stmts)
943 : {
944 726 : Node *stmt = lfirst(lc);
945 : Query *q;
946 726 : ParseState *pstate = make_parsestate(NULL);
947 :
948 726 : pstate->p_sourcetext = queryString;
949 726 : sql_fn_parser_setup(pstate, pinfo);
950 726 : q = transformStmt(pstate, stmt);
951 726 : if (q->commandType == CMD_UTILITY)
952 6 : ereport(ERROR,
953 : errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
954 : errmsg("%s is not yet supported in unquoted SQL function body",
955 : GetCommandTagName(CreateCommandTag(q->utilityStmt))));
956 720 : transformed_stmts = lappend(transformed_stmts, q);
957 720 : free_parsestate(pstate);
958 : }
959 :
960 722 : *sql_body_out = (Node *) list_make1(transformed_stmts);
961 : }
962 : else
963 : {
964 : Query *q;
965 4370 : ParseState *pstate = make_parsestate(NULL);
966 :
967 4370 : pstate->p_sourcetext = queryString;
968 4370 : sql_fn_parser_setup(pstate, pinfo);
969 4370 : q = transformStmt(pstate, sql_body_in);
970 4364 : if (q->commandType == CMD_UTILITY)
971 0 : ereport(ERROR,
972 : errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
973 : errmsg("%s is not yet supported in unquoted SQL function body",
974 : GetCommandTagName(CreateCommandTag(q->utilityStmt))));
975 4364 : free_parsestate(pstate);
976 :
977 4364 : *sql_body_out = (Node *) q;
978 : }
979 :
980 : /*
981 : * We must put something in prosrc. For the moment, just record an
982 : * empty string. It might be useful to store the original text of the
983 : * CREATE FUNCTION statement --- but to make actual use of that in
984 : * error reports, we'd also have to adjust readfuncs.c to not throw
985 : * away node location fields when reading prosqlbody.
986 : */
987 5086 : *prosrc_str_p = pstrdup("");
988 :
989 : /* But we definitely don't need probin. */
990 5086 : *probin_str_p = NULL;
991 : }
992 : else
993 : {
994 : /* Everything else wants the given string in prosrc. */
995 12162 : *prosrc_str_p = strVal(linitial(as));
996 12162 : *probin_str_p = NULL;
997 :
998 12162 : if (list_length(as) != 1)
999 6 : ereport(ERROR,
1000 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1001 : errmsg("only one AS item needed for language \"%s\"",
1002 : languageName)));
1003 :
1004 12156 : if (languageOid == INTERNALlanguageId)
1005 : {
1006 : /*
1007 : * In PostgreSQL versions before 6.5, the SQL name of the created
1008 : * function could not be different from the internal name, and
1009 : * "prosrc" wasn't used. So there is code out there that does
1010 : * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
1011 : * modicum of backwards compatibility, accept an empty "prosrc"
1012 : * value as meaning the supplied SQL function name.
1013 : */
1014 3864 : if (strlen(*prosrc_str_p) == 0)
1015 0 : *prosrc_str_p = funcname;
1016 : }
1017 : }
1018 22284 : }
1019 :
1020 :
1021 : /*
1022 : * CreateFunction
1023 : * Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement.
1024 : */
1025 : ObjectAddress
1026 22412 : CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
1027 : {
1028 : char *probin_str;
1029 : char *prosrc_str;
1030 : Node *prosqlbody;
1031 : Oid prorettype;
1032 : bool returnsSet;
1033 : char *language;
1034 : Oid languageOid;
1035 : Oid languageValidator;
1036 22412 : Node *transformDefElem = NULL;
1037 : char *funcname;
1038 : Oid namespaceId;
1039 : AclResult aclresult;
1040 : oidvector *parameterTypes;
1041 22412 : List *parameterTypes_list = NIL;
1042 : ArrayType *allParameterTypes;
1043 : ArrayType *parameterModes;
1044 : ArrayType *parameterNames;
1045 22412 : List *inParameterNames_list = NIL;
1046 : List *parameterDefaults;
1047 : Oid variadicArgType;
1048 22412 : List *trftypes_list = NIL;
1049 : ArrayType *trftypes;
1050 : Oid requiredResultType;
1051 : bool isWindowFunc,
1052 : isStrict,
1053 : security,
1054 : isLeakProof;
1055 : char volatility;
1056 : ArrayType *proconfig;
1057 : float4 procost;
1058 : float4 prorows;
1059 : Oid prosupport;
1060 : HeapTuple languageTuple;
1061 : Form_pg_language languageStruct;
1062 : List *as_clause;
1063 : char parallel;
1064 :
1065 : /* Convert list of names to a name and namespace */
1066 22412 : namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
1067 : &funcname);
1068 :
1069 : /* Check we have creation rights in target namespace */
1070 22412 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
1071 22412 : if (aclresult != ACLCHECK_OK)
1072 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
1073 0 : get_namespace_name(namespaceId));
1074 :
1075 : /* Set default attributes */
1076 22412 : as_clause = NIL;
1077 22412 : language = NULL;
1078 22412 : isWindowFunc = false;
1079 22412 : isStrict = false;
1080 22412 : security = false;
1081 22412 : isLeakProof = false;
1082 22412 : volatility = PROVOLATILE_VOLATILE;
1083 22412 : proconfig = NULL;
1084 22412 : procost = -1; /* indicates not set */
1085 22412 : prorows = -1; /* indicates not set */
1086 22412 : prosupport = InvalidOid;
1087 22412 : parallel = PROPARALLEL_UNSAFE;
1088 :
1089 : /* Extract non-default attributes from stmt->options list */
1090 22412 : compute_function_attributes(pstate,
1091 22412 : stmt->is_procedure,
1092 : stmt->options,
1093 : &as_clause, &language, &transformDefElem,
1094 : &isWindowFunc, &volatility,
1095 : &isStrict, &security, &isLeakProof,
1096 : &proconfig, &procost, &prorows,
1097 : &prosupport, ¶llel);
1098 :
1099 22400 : if (!language)
1100 : {
1101 64 : if (stmt->sql_body)
1102 64 : language = "sql";
1103 : else
1104 0 : ereport(ERROR,
1105 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1106 : errmsg("no language specified")));
1107 : }
1108 :
1109 : /* Look up the language and validate permissions */
1110 22400 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
1111 22400 : if (!HeapTupleIsValid(languageTuple))
1112 0 : ereport(ERROR,
1113 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1114 : errmsg("language \"%s\" does not exist", language),
1115 : (extension_file_exists(language) ?
1116 : errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
1117 :
1118 22400 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
1119 22400 : languageOid = languageStruct->oid;
1120 :
1121 22400 : if (languageStruct->lanpltrusted)
1122 : {
1123 : /* if trusted language, need USAGE privilege */
1124 12948 : aclresult = object_aclcheck(LanguageRelationId, languageOid, GetUserId(), ACL_USAGE);
1125 12948 : if (aclresult != ACLCHECK_OK)
1126 8 : aclcheck_error(aclresult, OBJECT_LANGUAGE,
1127 8 : NameStr(languageStruct->lanname));
1128 : }
1129 : else
1130 : {
1131 : /* if untrusted language, must be superuser */
1132 9452 : if (!superuser())
1133 0 : aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
1134 0 : NameStr(languageStruct->lanname));
1135 : }
1136 :
1137 22392 : languageValidator = languageStruct->lanvalidator;
1138 :
1139 22392 : ReleaseSysCache(languageTuple);
1140 :
1141 : /*
1142 : * Only superuser is allowed to create leakproof functions because
1143 : * leakproof functions can see tuples which have not yet been filtered out
1144 : * by security barrier views or row-level security policies.
1145 : */
1146 22392 : if (isLeakProof && !superuser())
1147 6 : ereport(ERROR,
1148 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1149 : errmsg("only superuser can define a leakproof function")));
1150 :
1151 22386 : if (transformDefElem)
1152 : {
1153 : ListCell *lc;
1154 :
1155 240 : foreach(lc, castNode(List, transformDefElem))
1156 : {
1157 122 : Oid typeid = typenameTypeId(NULL,
1158 122 : lfirst_node(TypeName, lc));
1159 122 : Oid elt = get_base_element_type(typeid);
1160 :
1161 122 : typeid = elt ? elt : typeid;
1162 :
1163 122 : get_transform_oid(typeid, languageOid, false);
1164 122 : trftypes_list = lappend_oid(trftypes_list, typeid);
1165 : }
1166 : }
1167 :
1168 : /*
1169 : * Convert remaining parameters of CREATE to form wanted by
1170 : * ProcedureCreate.
1171 : */
1172 22386 : interpret_function_parameter_list(pstate,
1173 : stmt->parameters,
1174 : languageOid,
1175 22386 : stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
1176 : ¶meterTypes,
1177 : ¶meterTypes_list,
1178 : &allParameterTypes,
1179 : ¶meterModes,
1180 : ¶meterNames,
1181 : &inParameterNames_list,
1182 : ¶meterDefaults,
1183 : &variadicArgType,
1184 : &requiredResultType);
1185 :
1186 22332 : if (stmt->is_procedure)
1187 : {
1188 : Assert(!stmt->returnType);
1189 336 : prorettype = requiredResultType ? requiredResultType : VOIDOID;
1190 336 : returnsSet = false;
1191 : }
1192 21996 : else if (stmt->returnType)
1193 : {
1194 : /* explicit RETURNS clause */
1195 21518 : compute_return_type(stmt->returnType, languageOid,
1196 : &prorettype, &returnsSet);
1197 21512 : if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1198 12 : ereport(ERROR,
1199 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1200 : errmsg("function result type must be %s because of OUT parameters",
1201 : format_type_be(requiredResultType))));
1202 : }
1203 478 : else if (OidIsValid(requiredResultType))
1204 : {
1205 : /* default RETURNS clause from OUT parameters */
1206 478 : prorettype = requiredResultType;
1207 478 : returnsSet = false;
1208 : }
1209 : else
1210 : {
1211 0 : ereport(ERROR,
1212 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1213 : errmsg("function result type must be specified")));
1214 : /* Alternative possibility: default to RETURNS VOID */
1215 : prorettype = VOIDOID;
1216 : returnsSet = false;
1217 : }
1218 :
1219 22314 : if (trftypes_list != NIL)
1220 : {
1221 : ListCell *lc;
1222 : Datum *arr;
1223 : int i;
1224 :
1225 118 : arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1226 118 : i = 0;
1227 240 : foreach(lc, trftypes_list)
1228 122 : arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1229 118 : trftypes = construct_array_builtin(arr, list_length(trftypes_list), OIDOID);
1230 : }
1231 : else
1232 : {
1233 : /* store SQL NULL instead of empty array */
1234 22196 : trftypes = NULL;
1235 : }
1236 :
1237 22314 : interpret_AS_clause(languageOid, language, funcname, as_clause, stmt->sql_body,
1238 : parameterTypes_list, inParameterNames_list,
1239 : &prosrc_str, &probin_str, &prosqlbody,
1240 : pstate->p_sourcetext);
1241 :
1242 : /*
1243 : * Set default values for COST and ROWS depending on other parameters;
1244 : * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1245 : * values, keep it in sync if you change them.
1246 : */
1247 22284 : if (procost < 0)
1248 : {
1249 : /* SQL and PL-language functions are assumed more expensive */
1250 18388 : if (languageOid == INTERNALlanguageId ||
1251 : languageOid == ClanguageId)
1252 8476 : procost = 1;
1253 : else
1254 9912 : procost = 100;
1255 : }
1256 22284 : if (prorows < 0)
1257 : {
1258 21744 : if (returnsSet)
1259 1758 : prorows = 1000;
1260 : else
1261 19986 : prorows = 0; /* dummy value if not returnsSet */
1262 : }
1263 540 : else if (!returnsSet)
1264 0 : ereport(ERROR,
1265 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1266 : errmsg("ROWS is not applicable when function does not return a set")));
1267 :
1268 : /*
1269 : * And now that we have all the parameters, and know we're permitted to do
1270 : * so, go ahead and create the function.
1271 : */
1272 44568 : return ProcedureCreate(funcname,
1273 : namespaceId,
1274 22284 : stmt->replace,
1275 : returnsSet,
1276 : prorettype,
1277 : GetUserId(),
1278 : languageOid,
1279 : languageValidator,
1280 : prosrc_str, /* converted to text later */
1281 : probin_str, /* converted to text later */
1282 : prosqlbody,
1283 22284 : stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
1284 : security,
1285 : isLeakProof,
1286 : isStrict,
1287 : volatility,
1288 : parallel,
1289 : parameterTypes,
1290 : PointerGetDatum(allParameterTypes),
1291 : PointerGetDatum(parameterModes),
1292 : PointerGetDatum(parameterNames),
1293 : parameterDefaults,
1294 : PointerGetDatum(trftypes),
1295 : PointerGetDatum(proconfig),
1296 : prosupport,
1297 : procost,
1298 : prorows);
1299 : }
1300 :
1301 : /*
1302 : * Guts of function deletion.
1303 : *
1304 : * Note: this is also used for aggregate deletion, since the OIDs of
1305 : * both functions and aggregates point to pg_proc.
1306 : */
1307 : void
1308 6750 : RemoveFunctionById(Oid funcOid)
1309 : {
1310 : Relation relation;
1311 : HeapTuple tup;
1312 : char prokind;
1313 :
1314 : /*
1315 : * Delete the pg_proc tuple.
1316 : */
1317 6750 : relation = table_open(ProcedureRelationId, RowExclusiveLock);
1318 :
1319 6750 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1320 6750 : if (!HeapTupleIsValid(tup)) /* should not happen */
1321 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1322 :
1323 6750 : prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
1324 :
1325 6750 : CatalogTupleDelete(relation, &tup->t_self);
1326 :
1327 6750 : ReleaseSysCache(tup);
1328 :
1329 6750 : table_close(relation, RowExclusiveLock);
1330 :
1331 6750 : pgstat_drop_function(funcOid);
1332 :
1333 : /*
1334 : * If there's a pg_aggregate tuple, delete that too.
1335 : */
1336 6750 : if (prokind == PROKIND_AGGREGATE)
1337 : {
1338 120 : relation = table_open(AggregateRelationId, RowExclusiveLock);
1339 :
1340 120 : tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1341 120 : if (!HeapTupleIsValid(tup)) /* should not happen */
1342 0 : elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1343 :
1344 120 : CatalogTupleDelete(relation, &tup->t_self);
1345 :
1346 120 : ReleaseSysCache(tup);
1347 :
1348 120 : table_close(relation, RowExclusiveLock);
1349 : }
1350 6750 : }
1351 :
1352 : /*
1353 : * Implements the ALTER FUNCTION utility command (except for the
1354 : * RENAME and OWNER clauses, which are handled as part of the generic
1355 : * ALTER framework).
1356 : */
1357 : ObjectAddress
1358 656 : AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
1359 : {
1360 : HeapTuple tup;
1361 : Oid funcOid;
1362 : Form_pg_proc procForm;
1363 : bool is_procedure;
1364 : Relation rel;
1365 : ListCell *l;
1366 656 : DefElem *volatility_item = NULL;
1367 656 : DefElem *strict_item = NULL;
1368 656 : DefElem *security_def_item = NULL;
1369 656 : DefElem *leakproof_item = NULL;
1370 656 : List *set_items = NIL;
1371 656 : DefElem *cost_item = NULL;
1372 656 : DefElem *rows_item = NULL;
1373 656 : DefElem *support_item = NULL;
1374 656 : DefElem *parallel_item = NULL;
1375 : ObjectAddress address;
1376 :
1377 656 : rel = table_open(ProcedureRelationId, RowExclusiveLock);
1378 :
1379 656 : funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1380 :
1381 638 : ObjectAddressSet(address, ProcedureRelationId, funcOid);
1382 :
1383 638 : tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1384 638 : if (!HeapTupleIsValid(tup)) /* should not happen */
1385 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1386 :
1387 638 : procForm = (Form_pg_proc) GETSTRUCT(tup);
1388 :
1389 : /* Permission check: must own function */
1390 638 : if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
1391 0 : aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
1392 0 : NameListToString(stmt->func->objname));
1393 :
1394 638 : if (procForm->prokind == PROKIND_AGGREGATE)
1395 0 : ereport(ERROR,
1396 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1397 : errmsg("\"%s\" is an aggregate function",
1398 : NameListToString(stmt->func->objname))));
1399 :
1400 638 : is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1401 :
1402 : /* Examine requested actions. */
1403 1270 : foreach(l, stmt->actions)
1404 : {
1405 638 : DefElem *defel = (DefElem *) lfirst(l);
1406 :
1407 638 : if (compute_common_attribute(pstate,
1408 : is_procedure,
1409 : defel,
1410 : &volatility_item,
1411 : &strict_item,
1412 : &security_def_item,
1413 : &leakproof_item,
1414 : &set_items,
1415 : &cost_item,
1416 : &rows_item,
1417 : &support_item,
1418 632 : ¶llel_item) == false)
1419 0 : elog(ERROR, "option \"%s\" not recognized", defel->defname);
1420 : }
1421 :
1422 632 : if (volatility_item)
1423 34 : procForm->provolatile = interpret_func_volatility(volatility_item);
1424 632 : if (strict_item)
1425 24 : procForm->proisstrict = boolVal(strict_item->arg);
1426 632 : if (security_def_item)
1427 12 : procForm->prosecdef = boolVal(security_def_item->arg);
1428 632 : if (leakproof_item)
1429 : {
1430 24 : procForm->proleakproof = boolVal(leakproof_item->arg);
1431 24 : if (procForm->proleakproof && !superuser())
1432 6 : ereport(ERROR,
1433 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1434 : errmsg("only superuser can define a leakproof function")));
1435 : }
1436 626 : if (cost_item)
1437 : {
1438 12 : procForm->procost = defGetNumeric(cost_item);
1439 12 : if (procForm->procost <= 0)
1440 0 : ereport(ERROR,
1441 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1442 : errmsg("COST must be positive")));
1443 : }
1444 626 : if (rows_item)
1445 : {
1446 0 : procForm->prorows = defGetNumeric(rows_item);
1447 0 : if (procForm->prorows <= 0)
1448 0 : ereport(ERROR,
1449 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1450 : errmsg("ROWS must be positive")));
1451 0 : if (!procForm->proretset)
1452 0 : ereport(ERROR,
1453 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1454 : errmsg("ROWS is not applicable when function does not return a set")));
1455 : }
1456 626 : if (support_item)
1457 : {
1458 : /* interpret_func_support handles the privilege check */
1459 6 : Oid newsupport = interpret_func_support(support_item);
1460 :
1461 : /* Add or replace dependency on support function */
1462 6 : if (OidIsValid(procForm->prosupport))
1463 : {
1464 0 : if (changeDependencyFor(ProcedureRelationId, funcOid,
1465 : ProcedureRelationId, procForm->prosupport,
1466 : newsupport) != 1)
1467 0 : elog(ERROR, "could not change support dependency for function %s",
1468 : get_func_name(funcOid));
1469 : }
1470 : else
1471 : {
1472 : ObjectAddress referenced;
1473 :
1474 6 : referenced.classId = ProcedureRelationId;
1475 6 : referenced.objectId = newsupport;
1476 6 : referenced.objectSubId = 0;
1477 6 : recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
1478 : }
1479 :
1480 6 : procForm->prosupport = newsupport;
1481 : }
1482 626 : if (parallel_item)
1483 502 : procForm->proparallel = interpret_func_parallel(parallel_item);
1484 626 : if (set_items)
1485 : {
1486 : Datum datum;
1487 : bool isnull;
1488 : ArrayType *a;
1489 : Datum repl_val[Natts_pg_proc];
1490 : bool repl_null[Natts_pg_proc];
1491 : bool repl_repl[Natts_pg_proc];
1492 :
1493 : /* extract existing proconfig setting */
1494 18 : datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1495 18 : a = isnull ? NULL : DatumGetArrayTypeP(datum);
1496 :
1497 : /* update according to each SET or RESET item, left to right */
1498 18 : a = update_proconfig_value(a, set_items);
1499 :
1500 : /* update the tuple */
1501 18 : memset(repl_repl, false, sizeof(repl_repl));
1502 18 : repl_repl[Anum_pg_proc_proconfig - 1] = true;
1503 :
1504 18 : if (a == NULL)
1505 : {
1506 12 : repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1507 12 : repl_null[Anum_pg_proc_proconfig - 1] = true;
1508 : }
1509 : else
1510 : {
1511 6 : repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1512 6 : repl_null[Anum_pg_proc_proconfig - 1] = false;
1513 : }
1514 :
1515 18 : tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1516 : repl_val, repl_null, repl_repl);
1517 : }
1518 : /* DO NOT put more touches of procForm below here; it's now dangling. */
1519 :
1520 : /* Do the update */
1521 626 : CatalogTupleUpdate(rel, &tup->t_self, tup);
1522 :
1523 626 : InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1524 :
1525 626 : table_close(rel, NoLock);
1526 626 : heap_freetuple(tup);
1527 :
1528 626 : return address;
1529 : }
1530 :
1531 :
1532 : /*
1533 : * CREATE CAST
1534 : */
1535 : ObjectAddress
1536 270 : CreateCast(CreateCastStmt *stmt)
1537 : {
1538 : Oid sourcetypeid;
1539 : Oid targettypeid;
1540 : char sourcetyptype;
1541 : char targettyptype;
1542 : Oid funcid;
1543 270 : Oid incastid = InvalidOid;
1544 270 : Oid outcastid = InvalidOid;
1545 : int nargs;
1546 : char castcontext;
1547 : char castmethod;
1548 : HeapTuple tuple;
1549 : AclResult aclresult;
1550 : ObjectAddress myself;
1551 :
1552 270 : sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
1553 270 : targettypeid = typenameTypeId(NULL, stmt->targettype);
1554 270 : sourcetyptype = get_typtype(sourcetypeid);
1555 270 : targettyptype = get_typtype(targettypeid);
1556 :
1557 : /* No pseudo-types allowed */
1558 270 : if (sourcetyptype == TYPTYPE_PSEUDO)
1559 0 : ereport(ERROR,
1560 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1561 : errmsg("source data type %s is a pseudo-type",
1562 : TypeNameToString(stmt->sourcetype))));
1563 :
1564 270 : if (targettyptype == TYPTYPE_PSEUDO)
1565 0 : ereport(ERROR,
1566 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1567 : errmsg("target data type %s is a pseudo-type",
1568 : TypeNameToString(stmt->targettype))));
1569 :
1570 : /* Permission check */
1571 270 : if (!object_ownercheck(TypeRelationId, sourcetypeid, GetUserId())
1572 12 : && !object_ownercheck(TypeRelationId, targettypeid, GetUserId()))
1573 0 : ereport(ERROR,
1574 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1575 : errmsg("must be owner of type %s or type %s",
1576 : format_type_be(sourcetypeid),
1577 : format_type_be(targettypeid))));
1578 :
1579 270 : aclresult = object_aclcheck(TypeRelationId, sourcetypeid, GetUserId(), ACL_USAGE);
1580 270 : if (aclresult != ACLCHECK_OK)
1581 6 : aclcheck_error_type(aclresult, sourcetypeid);
1582 :
1583 264 : aclresult = object_aclcheck(TypeRelationId, targettypeid, GetUserId(), ACL_USAGE);
1584 264 : if (aclresult != ACLCHECK_OK)
1585 0 : aclcheck_error_type(aclresult, targettypeid);
1586 :
1587 : /* Domains are allowed for historical reasons, but we warn */
1588 264 : if (sourcetyptype == TYPTYPE_DOMAIN)
1589 6 : ereport(WARNING,
1590 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1591 : errmsg("cast will be ignored because the source data type is a domain")));
1592 :
1593 258 : else if (targettyptype == TYPTYPE_DOMAIN)
1594 0 : ereport(WARNING,
1595 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1596 : errmsg("cast will be ignored because the target data type is a domain")));
1597 :
1598 : /* Determine the cast method */
1599 264 : if (stmt->func != NULL)
1600 96 : castmethod = COERCION_METHOD_FUNCTION;
1601 168 : else if (stmt->inout)
1602 6 : castmethod = COERCION_METHOD_INOUT;
1603 : else
1604 162 : castmethod = COERCION_METHOD_BINARY;
1605 :
1606 264 : if (castmethod == COERCION_METHOD_FUNCTION)
1607 : {
1608 : Form_pg_proc procstruct;
1609 :
1610 96 : funcid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->func, false);
1611 :
1612 96 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1613 96 : if (!HeapTupleIsValid(tuple))
1614 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1615 :
1616 96 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1617 96 : nargs = procstruct->pronargs;
1618 96 : if (nargs < 1 || nargs > 3)
1619 0 : ereport(ERROR,
1620 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1621 : errmsg("cast function must take one to three arguments")));
1622 96 : if (!IsBinaryCoercibleWithCast(sourcetypeid,
1623 : procstruct->proargtypes.values[0],
1624 : &incastid))
1625 0 : ereport(ERROR,
1626 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1627 : errmsg("argument of cast function must match or be binary-coercible from source data type")));
1628 96 : if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1629 0 : ereport(ERROR,
1630 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1631 : errmsg("second argument of cast function must be type %s",
1632 : "integer")));
1633 96 : if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1634 0 : ereport(ERROR,
1635 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1636 : errmsg("third argument of cast function must be type %s",
1637 : "boolean")));
1638 96 : if (!IsBinaryCoercibleWithCast(procstruct->prorettype,
1639 : targettypeid,
1640 : &outcastid))
1641 0 : ereport(ERROR,
1642 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1643 : errmsg("return data type of cast function must match or be binary-coercible to target data type")));
1644 :
1645 : /*
1646 : * Restricting the volatility of a cast function may or may not be a
1647 : * good idea in the abstract, but it definitely breaks many old
1648 : * user-defined types. Disable this check --- tgl 2/1/03
1649 : */
1650 : #ifdef NOT_USED
1651 : if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1652 : ereport(ERROR,
1653 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1654 : errmsg("cast function must not be volatile")));
1655 : #endif
1656 96 : if (procstruct->prokind != PROKIND_FUNCTION)
1657 0 : ereport(ERROR,
1658 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1659 : errmsg("cast function must be a normal function")));
1660 96 : if (procstruct->proretset)
1661 0 : ereport(ERROR,
1662 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1663 : errmsg("cast function must not return a set")));
1664 :
1665 96 : ReleaseSysCache(tuple);
1666 : }
1667 : else
1668 : {
1669 168 : funcid = InvalidOid;
1670 168 : nargs = 0;
1671 : }
1672 :
1673 264 : if (castmethod == COERCION_METHOD_BINARY)
1674 : {
1675 : int16 typ1len;
1676 : int16 typ2len;
1677 : bool typ1byval;
1678 : bool typ2byval;
1679 : char typ1align;
1680 : char typ2align;
1681 :
1682 : /*
1683 : * Must be superuser to create binary-compatible casts, since
1684 : * erroneous casts can easily crash the backend.
1685 : */
1686 162 : if (!superuser())
1687 0 : ereport(ERROR,
1688 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1689 : errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1690 :
1691 : /*
1692 : * Also, insist that the types match as to size, alignment, and
1693 : * pass-by-value attributes; this provides at least a crude check that
1694 : * they have similar representations. A pair of types that fail this
1695 : * test should certainly not be equated.
1696 : */
1697 162 : get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1698 162 : get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1699 162 : if (typ1len != typ2len ||
1700 162 : typ1byval != typ2byval ||
1701 162 : typ1align != typ2align)
1702 0 : ereport(ERROR,
1703 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1704 : errmsg("source and target data types are not physically compatible")));
1705 :
1706 : /*
1707 : * We know that composite, array, range and enum types are never
1708 : * binary-compatible with each other. They all have OIDs embedded in
1709 : * them.
1710 : *
1711 : * Theoretically you could build a user-defined base type that is
1712 : * binary-compatible with such a type. But we disallow it anyway, as
1713 : * in practice such a cast is surely a mistake. You can always work
1714 : * around that by writing a cast function.
1715 : *
1716 : * NOTE: if we ever have a kind of container type that doesn't need to
1717 : * be rejected for this reason, we'd likely need to recursively apply
1718 : * all of these same checks to the contained type(s).
1719 : */
1720 162 : if (sourcetyptype == TYPTYPE_COMPOSITE ||
1721 : targettyptype == TYPTYPE_COMPOSITE)
1722 0 : ereport(ERROR,
1723 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1724 : errmsg("composite data types are not binary-compatible")));
1725 :
1726 324 : if (OidIsValid(get_element_type(sourcetypeid)) ||
1727 162 : OidIsValid(get_element_type(targettypeid)))
1728 0 : ereport(ERROR,
1729 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1730 : errmsg("array data types are not binary-compatible")));
1731 :
1732 162 : if (sourcetyptype == TYPTYPE_RANGE ||
1733 162 : targettyptype == TYPTYPE_RANGE ||
1734 162 : sourcetyptype == TYPTYPE_MULTIRANGE ||
1735 : targettyptype == TYPTYPE_MULTIRANGE)
1736 0 : ereport(ERROR,
1737 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1738 : errmsg("range data types are not binary-compatible")));
1739 :
1740 162 : if (sourcetyptype == TYPTYPE_ENUM ||
1741 : targettyptype == TYPTYPE_ENUM)
1742 0 : ereport(ERROR,
1743 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1744 : errmsg("enum data types are not binary-compatible")));
1745 :
1746 : /*
1747 : * We also disallow creating binary-compatibility casts involving
1748 : * domains. Casting from a domain to its base type is already
1749 : * allowed, and casting the other way ought to go through domain
1750 : * coercion to permit constraint checking. Again, if you're intent on
1751 : * having your own semantics for that, create a no-op cast function.
1752 : *
1753 : * NOTE: if we were to relax this, the above checks for composites
1754 : * etc. would have to be modified to look through domains to their
1755 : * base types.
1756 : */
1757 162 : if (sourcetyptype == TYPTYPE_DOMAIN ||
1758 : targettyptype == TYPTYPE_DOMAIN)
1759 0 : ereport(ERROR,
1760 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1761 : errmsg("domain data types must not be marked binary-compatible")));
1762 : }
1763 :
1764 : /*
1765 : * Allow source and target types to be same only for length coercion
1766 : * functions. We assume a multi-arg function does length coercion.
1767 : */
1768 264 : if (sourcetypeid == targettypeid && nargs < 2)
1769 0 : ereport(ERROR,
1770 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1771 : errmsg("source data type and target data type are the same")));
1772 :
1773 : /* convert CoercionContext enum to char value for castcontext */
1774 264 : switch (stmt->context)
1775 : {
1776 30 : case COERCION_IMPLICIT:
1777 30 : castcontext = COERCION_CODE_IMPLICIT;
1778 30 : break;
1779 58 : case COERCION_ASSIGNMENT:
1780 58 : castcontext = COERCION_CODE_ASSIGNMENT;
1781 58 : break;
1782 : /* COERCION_PLPGSQL is intentionally not covered here */
1783 176 : case COERCION_EXPLICIT:
1784 176 : castcontext = COERCION_CODE_EXPLICIT;
1785 176 : break;
1786 0 : default:
1787 0 : elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1788 : castcontext = 0; /* keep compiler quiet */
1789 : break;
1790 : }
1791 :
1792 264 : myself = CastCreate(sourcetypeid, targettypeid, funcid, incastid, outcastid,
1793 : castcontext, castmethod, DEPENDENCY_NORMAL);
1794 264 : return myself;
1795 : }
1796 :
1797 :
1798 : static void
1799 80 : check_transform_function(Form_pg_proc procstruct)
1800 : {
1801 80 : if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1802 0 : ereport(ERROR,
1803 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1804 : errmsg("transform function must not be volatile")));
1805 80 : if (procstruct->prokind != PROKIND_FUNCTION)
1806 0 : ereport(ERROR,
1807 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1808 : errmsg("transform function must be a normal function")));
1809 80 : if (procstruct->proretset)
1810 0 : ereport(ERROR,
1811 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1812 : errmsg("transform function must not return a set")));
1813 80 : if (procstruct->pronargs != 1)
1814 0 : ereport(ERROR,
1815 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1816 : errmsg("transform function must take one argument")));
1817 80 : if (procstruct->proargtypes.values[0] != INTERNALOID)
1818 2 : ereport(ERROR,
1819 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1820 : errmsg("first argument of transform function must be type %s",
1821 : "internal")));
1822 78 : }
1823 :
1824 :
1825 : /*
1826 : * CREATE TRANSFORM
1827 : */
1828 : ObjectAddress
1829 50 : CreateTransform(CreateTransformStmt *stmt)
1830 : {
1831 : Oid typeid;
1832 : char typtype;
1833 : Oid langid;
1834 : Oid fromsqlfuncid;
1835 : Oid tosqlfuncid;
1836 : AclResult aclresult;
1837 : Form_pg_proc procstruct;
1838 : Datum values[Natts_pg_transform];
1839 50 : bool nulls[Natts_pg_transform] = {0};
1840 50 : bool replaces[Natts_pg_transform] = {0};
1841 : Oid transformid;
1842 : HeapTuple tuple;
1843 : HeapTuple newtuple;
1844 : Relation relation;
1845 : ObjectAddress myself,
1846 : referenced;
1847 : ObjectAddresses *addrs;
1848 : bool is_replace;
1849 :
1850 : /*
1851 : * Get the type
1852 : */
1853 50 : typeid = typenameTypeId(NULL, stmt->type_name);
1854 48 : typtype = get_typtype(typeid);
1855 :
1856 48 : if (typtype == TYPTYPE_PSEUDO)
1857 0 : ereport(ERROR,
1858 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1859 : errmsg("data type %s is a pseudo-type",
1860 : TypeNameToString(stmt->type_name))));
1861 :
1862 48 : if (typtype == TYPTYPE_DOMAIN)
1863 0 : ereport(ERROR,
1864 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1865 : errmsg("data type %s is a domain",
1866 : TypeNameToString(stmt->type_name))));
1867 :
1868 48 : if (!object_ownercheck(TypeRelationId, typeid, GetUserId()))
1869 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
1870 :
1871 48 : aclresult = object_aclcheck(TypeRelationId, typeid, GetUserId(), ACL_USAGE);
1872 48 : if (aclresult != ACLCHECK_OK)
1873 0 : aclcheck_error_type(aclresult, typeid);
1874 :
1875 : /*
1876 : * Get the language
1877 : */
1878 48 : langid = get_language_oid(stmt->lang, false);
1879 :
1880 46 : aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE);
1881 46 : if (aclresult != ACLCHECK_OK)
1882 0 : aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang);
1883 :
1884 : /*
1885 : * Get the functions
1886 : */
1887 46 : if (stmt->fromsql)
1888 : {
1889 44 : fromsqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->fromsql, false);
1890 :
1891 44 : if (!object_ownercheck(ProcedureRelationId, fromsqlfuncid, GetUserId()))
1892 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
1893 :
1894 44 : aclresult = object_aclcheck(ProcedureRelationId, fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1895 44 : if (aclresult != ACLCHECK_OK)
1896 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
1897 :
1898 44 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1899 44 : if (!HeapTupleIsValid(tuple))
1900 0 : elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1901 44 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1902 44 : if (procstruct->prorettype != INTERNALOID)
1903 2 : ereport(ERROR,
1904 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1905 : errmsg("return data type of FROM SQL function must be %s",
1906 : "internal")));
1907 42 : check_transform_function(procstruct);
1908 40 : ReleaseSysCache(tuple);
1909 : }
1910 : else
1911 2 : fromsqlfuncid = InvalidOid;
1912 :
1913 42 : if (stmt->tosql)
1914 : {
1915 38 : tosqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->tosql, false);
1916 :
1917 38 : if (!object_ownercheck(ProcedureRelationId, tosqlfuncid, GetUserId()))
1918 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
1919 :
1920 38 : aclresult = object_aclcheck(ProcedureRelationId, tosqlfuncid, GetUserId(), ACL_EXECUTE);
1921 38 : if (aclresult != ACLCHECK_OK)
1922 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
1923 :
1924 38 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1925 38 : if (!HeapTupleIsValid(tuple))
1926 0 : elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1927 38 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1928 38 : if (procstruct->prorettype != typeid)
1929 0 : ereport(ERROR,
1930 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1931 : errmsg("return data type of TO SQL function must be the transform data type")));
1932 38 : check_transform_function(procstruct);
1933 38 : ReleaseSysCache(tuple);
1934 : }
1935 : else
1936 4 : tosqlfuncid = InvalidOid;
1937 :
1938 : /*
1939 : * Ready to go
1940 : */
1941 42 : values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1942 42 : values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1943 42 : values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1944 42 : values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1945 :
1946 42 : relation = table_open(TransformRelationId, RowExclusiveLock);
1947 :
1948 42 : tuple = SearchSysCache2(TRFTYPELANG,
1949 : ObjectIdGetDatum(typeid),
1950 : ObjectIdGetDatum(langid));
1951 42 : if (HeapTupleIsValid(tuple))
1952 : {
1953 8 : Form_pg_transform form = (Form_pg_transform) GETSTRUCT(tuple);
1954 :
1955 8 : if (!stmt->replace)
1956 2 : ereport(ERROR,
1957 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1958 : errmsg("transform for type %s language \"%s\" already exists",
1959 : format_type_be(typeid),
1960 : stmt->lang)));
1961 :
1962 6 : replaces[Anum_pg_transform_trffromsql - 1] = true;
1963 6 : replaces[Anum_pg_transform_trftosql - 1] = true;
1964 :
1965 6 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1966 6 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1967 :
1968 6 : transformid = form->oid;
1969 6 : ReleaseSysCache(tuple);
1970 6 : is_replace = true;
1971 : }
1972 : else
1973 : {
1974 34 : transformid = GetNewOidWithIndex(relation, TransformOidIndexId,
1975 : Anum_pg_transform_oid);
1976 34 : values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid);
1977 34 : newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1978 34 : CatalogTupleInsert(relation, newtuple);
1979 34 : is_replace = false;
1980 : }
1981 :
1982 40 : if (is_replace)
1983 6 : deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1984 :
1985 40 : addrs = new_object_addresses();
1986 :
1987 : /* make dependency entries */
1988 40 : ObjectAddressSet(myself, TransformRelationId, transformid);
1989 :
1990 : /* dependency on language */
1991 40 : ObjectAddressSet(referenced, LanguageRelationId, langid);
1992 40 : add_exact_object_address(&referenced, addrs);
1993 :
1994 : /* dependency on type */
1995 40 : ObjectAddressSet(referenced, TypeRelationId, typeid);
1996 40 : add_exact_object_address(&referenced, addrs);
1997 :
1998 : /* dependencies on functions */
1999 40 : if (OidIsValid(fromsqlfuncid))
2000 : {
2001 38 : ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
2002 38 : add_exact_object_address(&referenced, addrs);
2003 : }
2004 40 : if (OidIsValid(tosqlfuncid))
2005 : {
2006 36 : ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
2007 36 : add_exact_object_address(&referenced, addrs);
2008 : }
2009 :
2010 40 : record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
2011 40 : free_object_addresses(addrs);
2012 :
2013 : /* dependency on extension */
2014 40 : recordDependencyOnCurrentExtension(&myself, is_replace);
2015 :
2016 : /* Post creation hook for new transform */
2017 40 : InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
2018 :
2019 40 : heap_freetuple(newtuple);
2020 :
2021 40 : table_close(relation, RowExclusiveLock);
2022 :
2023 40 : return myself;
2024 : }
2025 :
2026 :
2027 : /*
2028 : * get_transform_oid - given type OID and language OID, look up a transform OID
2029 : *
2030 : * If missing_ok is false, throw an error if the transform is not found. If
2031 : * true, just return InvalidOid.
2032 : */
2033 : Oid
2034 75194 : get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
2035 : {
2036 : Oid oid;
2037 :
2038 75194 : oid = GetSysCacheOid2(TRFTYPELANG, Anum_pg_transform_oid,
2039 : ObjectIdGetDatum(type_id),
2040 : ObjectIdGetDatum(lang_id));
2041 75194 : if (!OidIsValid(oid) && !missing_ok)
2042 0 : ereport(ERROR,
2043 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2044 : errmsg("transform for type %s language \"%s\" does not exist",
2045 : format_type_be(type_id),
2046 : get_language_name(lang_id, false))));
2047 75194 : return oid;
2048 : }
2049 :
2050 :
2051 : /*
2052 : * Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA/RENAME
2053 : *
2054 : * Is there a function with the given name and signature already in the given
2055 : * namespace? If so, raise an appropriate error message.
2056 : */
2057 : void
2058 136 : IsThereFunctionInNamespace(const char *proname, int pronargs,
2059 : oidvector *proargtypes, Oid nspOid)
2060 : {
2061 : /* check for duplicate name (more friendly than unique-index failure) */
2062 136 : if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2063 : CStringGetDatum(proname),
2064 : PointerGetDatum(proargtypes),
2065 : ObjectIdGetDatum(nspOid)))
2066 24 : ereport(ERROR,
2067 : (errcode(ERRCODE_DUPLICATE_FUNCTION),
2068 : errmsg("function %s already exists in schema \"%s\"",
2069 : funcname_signature_string(proname, pronargs,
2070 : NIL, proargtypes->values),
2071 : get_namespace_name(nspOid))));
2072 112 : }
2073 :
2074 : /*
2075 : * ExecuteDoStmt
2076 : * Execute inline procedural-language code
2077 : *
2078 : * See at ExecuteCallStmt() about the atomic argument.
2079 : */
2080 : void
2081 1550 : ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic)
2082 : {
2083 1550 : InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
2084 : ListCell *arg;
2085 1550 : DefElem *as_item = NULL;
2086 1550 : DefElem *language_item = NULL;
2087 : char *language;
2088 : Oid laninline;
2089 : HeapTuple languageTuple;
2090 : Form_pg_language languageStruct;
2091 :
2092 : /* Process options we got from gram.y */
2093 3298 : foreach(arg, stmt->args)
2094 : {
2095 1748 : DefElem *defel = (DefElem *) lfirst(arg);
2096 :
2097 1748 : if (strcmp(defel->defname, "as") == 0)
2098 : {
2099 1550 : if (as_item)
2100 0 : errorConflictingDefElem(defel, pstate);
2101 1550 : as_item = defel;
2102 : }
2103 198 : else if (strcmp(defel->defname, "language") == 0)
2104 : {
2105 198 : if (language_item)
2106 0 : errorConflictingDefElem(defel, pstate);
2107 198 : language_item = defel;
2108 : }
2109 : else
2110 0 : elog(ERROR, "option \"%s\" not recognized",
2111 : defel->defname);
2112 : }
2113 :
2114 1550 : if (as_item)
2115 1550 : codeblock->source_text = strVal(as_item->arg);
2116 : else
2117 0 : ereport(ERROR,
2118 : (errcode(ERRCODE_SYNTAX_ERROR),
2119 : errmsg("no inline code specified")));
2120 :
2121 : /* if LANGUAGE option wasn't specified, use the default */
2122 1550 : if (language_item)
2123 198 : language = strVal(language_item->arg);
2124 : else
2125 1352 : language = "plpgsql";
2126 :
2127 : /* Look up the language and validate permissions */
2128 1550 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2129 1550 : if (!HeapTupleIsValid(languageTuple))
2130 0 : ereport(ERROR,
2131 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2132 : errmsg("language \"%s\" does not exist", language),
2133 : (extension_file_exists(language) ?
2134 : errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
2135 :
2136 1550 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2137 1550 : codeblock->langOid = languageStruct->oid;
2138 1550 : codeblock->langIsTrusted = languageStruct->lanpltrusted;
2139 1550 : codeblock->atomic = atomic;
2140 :
2141 1550 : if (languageStruct->lanpltrusted)
2142 : {
2143 : /* if trusted language, need USAGE privilege */
2144 : AclResult aclresult;
2145 :
2146 1506 : aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(),
2147 : ACL_USAGE);
2148 1506 : if (aclresult != ACLCHECK_OK)
2149 0 : aclcheck_error(aclresult, OBJECT_LANGUAGE,
2150 0 : NameStr(languageStruct->lanname));
2151 : }
2152 : else
2153 : {
2154 : /* if untrusted language, must be superuser */
2155 44 : if (!superuser())
2156 0 : aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
2157 0 : NameStr(languageStruct->lanname));
2158 : }
2159 :
2160 : /* get the handler function's OID */
2161 1550 : laninline = languageStruct->laninline;
2162 1550 : if (!OidIsValid(laninline))
2163 0 : ereport(ERROR,
2164 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2165 : errmsg("language \"%s\" does not support inline code execution",
2166 : NameStr(languageStruct->lanname))));
2167 :
2168 1550 : ReleaseSysCache(languageTuple);
2169 :
2170 : /* execute the inline handler */
2171 1550 : OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2172 1148 : }
2173 :
2174 : /*
2175 : * Execute CALL statement
2176 : *
2177 : * Inside a top-level CALL statement, transaction-terminating commands such as
2178 : * COMMIT or a PL-specific equivalent are allowed. The terminology in the SQL
2179 : * standard is that CALL establishes a non-atomic execution context. Most
2180 : * other commands establish an atomic execution context, in which transaction
2181 : * control actions are not allowed. If there are nested executions of CALL,
2182 : * we want to track the execution context recursively, so that the nested
2183 : * CALLs can also do transaction control. Note, however, that for example in
2184 : * CALL -> SELECT -> CALL, the second call cannot do transaction control,
2185 : * because the SELECT in between establishes an atomic execution context.
2186 : *
2187 : * So when ExecuteCallStmt() is called from the top level, we pass in atomic =
2188 : * false (recall that that means transactions = yes). We then create a
2189 : * CallContext node with content atomic = false, which is passed in the
2190 : * fcinfo->context field to the procedure invocation. The language
2191 : * implementation should then take appropriate measures to allow or prevent
2192 : * transaction commands based on that information, e.g., call
2193 : * SPI_connect_ext(SPI_OPT_NONATOMIC). The language should also pass on the
2194 : * atomic flag to any nested invocations to CALL.
2195 : *
2196 : * The expression data structures and execution context that we create
2197 : * within this function are children of the portalContext of the Portal
2198 : * that the CALL utility statement runs in. Therefore, any pass-by-ref
2199 : * values that we're passing to the procedure will survive transaction
2200 : * commits that might occur inside the procedure.
2201 : */
2202 : void
2203 466 : ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
2204 : {
2205 466 : LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
2206 : ListCell *lc;
2207 : FuncExpr *fexpr;
2208 : int nargs;
2209 : int i;
2210 : AclResult aclresult;
2211 : FmgrInfo flinfo;
2212 : CallContext *callcontext;
2213 : EState *estate;
2214 : ExprContext *econtext;
2215 : HeapTuple tp;
2216 : PgStat_FunctionCallUsage fcusage;
2217 : Datum retval;
2218 :
2219 466 : fexpr = stmt->funcexpr;
2220 : Assert(fexpr);
2221 : Assert(IsA(fexpr, FuncExpr));
2222 :
2223 466 : aclresult = object_aclcheck(ProcedureRelationId, fexpr->funcid, GetUserId(), ACL_EXECUTE);
2224 466 : if (aclresult != ACLCHECK_OK)
2225 12 : aclcheck_error(aclresult, OBJECT_PROCEDURE, get_func_name(fexpr->funcid));
2226 :
2227 : /* Prep the context object we'll pass to the procedure */
2228 454 : callcontext = makeNode(CallContext);
2229 454 : callcontext->atomic = atomic;
2230 :
2231 454 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2232 454 : if (!HeapTupleIsValid(tp))
2233 0 : elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
2234 :
2235 : /*
2236 : * If proconfig is set we can't allow transaction commands because of the
2237 : * way the GUC stacking works: The transaction boundary would have to pop
2238 : * the proconfig setting off the stack. That restriction could be lifted
2239 : * by redesigning the GUC nesting mechanism a bit.
2240 : */
2241 454 : if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL))
2242 2 : callcontext->atomic = true;
2243 :
2244 : /*
2245 : * In security definer procedures, we can't allow transaction commands.
2246 : * StartTransaction() insists that the security context stack is empty,
2247 : * and AbortTransaction() resets the security context. This could be
2248 : * reorganized, but right now it doesn't work.
2249 : */
2250 454 : if (((Form_pg_proc) GETSTRUCT(tp))->prosecdef)
2251 2 : callcontext->atomic = true;
2252 :
2253 454 : ReleaseSysCache(tp);
2254 :
2255 : /* safety check; see ExecInitFunc() */
2256 454 : nargs = list_length(fexpr->args);
2257 454 : if (nargs > FUNC_MAX_ARGS)
2258 0 : ereport(ERROR,
2259 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2260 : errmsg_plural("cannot pass more than %d argument to a procedure",
2261 : "cannot pass more than %d arguments to a procedure",
2262 : FUNC_MAX_ARGS,
2263 : FUNC_MAX_ARGS)));
2264 :
2265 : /* Initialize function call structure */
2266 454 : InvokeFunctionExecuteHook(fexpr->funcid);
2267 454 : fmgr_info(fexpr->funcid, &flinfo);
2268 454 : fmgr_info_set_expr((Node *) fexpr, &flinfo);
2269 454 : InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
2270 : (Node *) callcontext, NULL);
2271 :
2272 : /*
2273 : * Evaluate procedure arguments inside a suitable execution context. Note
2274 : * we can't free this context till the procedure returns.
2275 : */
2276 454 : estate = CreateExecutorState();
2277 454 : estate->es_param_list_info = params;
2278 454 : econtext = CreateExprContext(estate);
2279 :
2280 : /*
2281 : * If we're called in non-atomic context, we also have to ensure that the
2282 : * argument expressions run with an up-to-date snapshot. Our caller will
2283 : * have provided a current snapshot in atomic contexts, but not in
2284 : * non-atomic contexts, because the possibility of a COMMIT/ROLLBACK
2285 : * destroying the snapshot makes higher-level management too complicated.
2286 : */
2287 454 : if (!atomic)
2288 416 : PushActiveSnapshot(GetTransactionSnapshot());
2289 :
2290 454 : i = 0;
2291 1082 : foreach(lc, fexpr->args)
2292 : {
2293 : ExprState *exprstate;
2294 : Datum val;
2295 : bool isnull;
2296 :
2297 628 : exprstate = ExecPrepareExpr(lfirst(lc), estate);
2298 :
2299 628 : val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
2300 :
2301 628 : fcinfo->args[i].value = val;
2302 628 : fcinfo->args[i].isnull = isnull;
2303 :
2304 628 : i++;
2305 : }
2306 :
2307 : /* Get rid of temporary snapshot for arguments, if we made one */
2308 454 : if (!atomic)
2309 416 : PopActiveSnapshot();
2310 :
2311 : /* Here we actually call the procedure */
2312 454 : pgstat_init_function_usage(fcinfo, &fcusage);
2313 454 : retval = FunctionCallInvoke(fcinfo);
2314 422 : pgstat_end_function_usage(&fcusage, true);
2315 :
2316 : /* Handle the procedure's outputs */
2317 422 : if (fexpr->funcresulttype == VOIDOID)
2318 : {
2319 : /* do nothing */
2320 : }
2321 202 : else if (fexpr->funcresulttype == RECORDOID)
2322 : {
2323 : /* send tuple to client */
2324 : HeapTupleHeader td;
2325 : Oid tupType;
2326 : int32 tupTypmod;
2327 : TupleDesc retdesc;
2328 : HeapTupleData rettupdata;
2329 : TupOutputState *tstate;
2330 : TupleTableSlot *slot;
2331 :
2332 202 : if (fcinfo->isnull)
2333 0 : elog(ERROR, "procedure returned null record");
2334 :
2335 : /*
2336 : * Ensure there's an active snapshot whilst we execute whatever's
2337 : * involved here. Note that this is *not* sufficient to make the
2338 : * world safe for TOAST pointers to be included in the returned data:
2339 : * the referenced data could have gone away while we didn't hold a
2340 : * snapshot. Hence, it's incumbent on PLs that can do COMMIT/ROLLBACK
2341 : * to not return TOAST pointers, unless those pointers were fetched
2342 : * after the last COMMIT/ROLLBACK in the procedure.
2343 : *
2344 : * XXX that is a really nasty, hard-to-test requirement. Is there a
2345 : * way to remove it?
2346 : */
2347 202 : EnsurePortalSnapshotExists();
2348 :
2349 202 : td = DatumGetHeapTupleHeader(retval);
2350 202 : tupType = HeapTupleHeaderGetTypeId(td);
2351 202 : tupTypmod = HeapTupleHeaderGetTypMod(td);
2352 202 : retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
2353 :
2354 202 : tstate = begin_tup_output_tupdesc(dest, retdesc,
2355 : &TTSOpsHeapTuple);
2356 :
2357 202 : rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
2358 202 : ItemPointerSetInvalid(&(rettupdata.t_self));
2359 202 : rettupdata.t_tableOid = InvalidOid;
2360 202 : rettupdata.t_data = td;
2361 :
2362 202 : slot = ExecStoreHeapTuple(&rettupdata, tstate->slot, false);
2363 202 : tstate->dest->receiveSlot(slot, tstate->dest);
2364 :
2365 202 : end_tup_output(tstate);
2366 :
2367 202 : ReleaseTupleDesc(retdesc);
2368 : }
2369 : else
2370 0 : elog(ERROR, "unexpected result type for procedure: %u",
2371 : fexpr->funcresulttype);
2372 :
2373 422 : FreeExecutorState(estate);
2374 422 : }
2375 :
2376 : /*
2377 : * Construct the tuple descriptor for a CALL statement return
2378 : */
2379 : TupleDesc
2380 196 : CallStmtResultDesc(CallStmt *stmt)
2381 : {
2382 : FuncExpr *fexpr;
2383 : HeapTuple tuple;
2384 : TupleDesc tupdesc;
2385 :
2386 196 : fexpr = stmt->funcexpr;
2387 :
2388 196 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2389 196 : if (!HeapTupleIsValid(tuple))
2390 0 : elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
2391 :
2392 196 : tupdesc = build_function_result_tupdesc_t(tuple);
2393 :
2394 196 : ReleaseSysCache(tuple);
2395 :
2396 : /*
2397 : * The result of build_function_result_tupdesc_t has the right column
2398 : * names, but it just has the declared output argument types, which is the
2399 : * wrong thing in polymorphic cases. Get the correct types by examining
2400 : * stmt->outargs. We intentionally keep the atttypmod as -1 and the
2401 : * attcollation as the type's default, since that's always the appropriate
2402 : * thing for function outputs; there's no point in considering any
2403 : * additional info available from outargs. Note that tupdesc is null if
2404 : * there are no outargs.
2405 : */
2406 196 : if (tupdesc)
2407 : {
2408 : Assert(tupdesc->natts == list_length(stmt->outargs));
2409 502 : for (int i = 0; i < tupdesc->natts; i++)
2410 : {
2411 306 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2412 306 : Node *outarg = (Node *) list_nth(stmt->outargs, i);
2413 :
2414 306 : TupleDescInitEntry(tupdesc,
2415 306 : i + 1,
2416 306 : NameStr(att->attname),
2417 : exprType(outarg),
2418 : -1,
2419 : 0);
2420 : }
2421 : }
2422 :
2423 196 : return tupdesc;
2424 : }
|