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