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 23562 : 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 23562 : typtup = LookupTypeName(NULL, returnType, NULL, false);
96 :
97 23562 : if (typtup)
98 : {
99 23488 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
100 : {
101 170 : 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 170 : ereport(NOTICE,
108 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
109 : errmsg("return type %s is only a shell",
110 : TypeNameToString(returnType))));
111 : }
112 23488 : rettype = typeTypeId(typtup);
113 23488 : 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 23562 : aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
159 23562 : if (aclresult != ACLCHECK_OK)
160 6 : aclcheck_error_type(aclresult, rettype);
161 :
162 23556 : *prorettype_p = rettype;
163 23556 : *returnsSet_p = returnType->setof;
164 23556 : }
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 25102 : 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 25102 : int parameterCount = list_length(parameters);
198 : Oid *inTypes;
199 25102 : int inCount = 0;
200 : Datum *allTypes;
201 : Datum *paramModes;
202 : Datum *paramNames;
203 25102 : int outCount = 0;
204 25102 : int varCount = 0;
205 25102 : bool have_names = false;
206 25102 : bool have_defaults = false;
207 : ListCell *x;
208 : int i;
209 :
210 25102 : *variadicArgType = InvalidOid; /* default result */
211 25102 : *requiredResultType = InvalidOid; /* default result */
212 :
213 25102 : inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
214 25102 : allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
215 25102 : paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
216 25102 : paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
217 25102 : *parameterDefaults = NIL;
218 :
219 : /* Scan the list and extract data into work arrays */
220 25102 : i = 0;
221 78966 : foreach(x, parameters)
222 : {
223 53924 : FunctionParameter *fp = (FunctionParameter *) lfirst(x);
224 53924 : TypeName *t = fp->argType;
225 53924 : FunctionParameterMode fpmode = fp->mode;
226 53924 : 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 53924 : if (fpmode == FUNC_PARAM_DEFAULT)
233 37218 : fpmode = FUNC_PARAM_IN;
234 :
235 53924 : typtup = LookupTypeName(pstate, t, NULL, false);
236 53924 : if (typtup)
237 : {
238 53924 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
239 : {
240 : /* As above, hard error if language is SQL */
241 238 : 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 238 : 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 238 : 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 53924 : toid = typeTypeId(typtup);
262 53924 : 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 53924 : aclresult = object_aclcheck(TypeRelationId, toid, GetUserId(), ACL_USAGE);
275 53924 : if (aclresult != ACLCHECK_OK)
276 12 : aclcheck_error_type(aclresult, toid);
277 :
278 53912 : 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 53912 : if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
299 : {
300 : /* other input parameters can't follow a VARIADIC parameter */
301 41582 : 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 41582 : inTypes[inCount++] = toid;
307 41582 : isinput = true;
308 41582 : if (parameterTypes_list)
309 40958 : *parameterTypes_list = lappend_oid(*parameterTypes_list, toid);
310 : }
311 :
312 : /* handle output parameters */
313 53912 : if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
314 : {
315 12522 : 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 208 : 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 202 : *requiredResultType = RECORDOID;
329 : }
330 12314 : else if (outCount == 0) /* save first output param's type */
331 2414 : *requiredResultType = toid;
332 12516 : outCount++;
333 : }
334 :
335 53906 : if (fpmode == FUNC_PARAM_VARIADIC)
336 : {
337 506 : *variadicArgType = toid;
338 506 : varCount++;
339 : /* validate variadic parameter type */
340 506 : switch (toid)
341 : {
342 82 : case ANYARRAYOID:
343 : case ANYCOMPATIBLEARRAYOID:
344 : case ANYOID:
345 : /* okay */
346 82 : break;
347 424 : default:
348 424 : 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 424 : break;
354 : }
355 53400 : }
356 :
357 53906 : allTypes[i] = ObjectIdGetDatum(toid);
358 :
359 53906 : paramModes[i] = CharGetDatum(fpmode);
360 :
361 53906 : 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 156384 : foreach(px, parameters)
372 : {
373 156384 : FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
374 : FunctionParameterMode prevfpmode;
375 :
376 156384 : if (prevfp == fp)
377 31376 : break;
378 : /* as above, default mode is IN */
379 125008 : prevfpmode = prevfp->mode;
380 125008 : if (prevfpmode == FUNC_PARAM_DEFAULT)
381 21092 : prevfpmode = FUNC_PARAM_IN;
382 : /* pure in doesn't conflict with pure out */
383 125008 : if ((fpmode == FUNC_PARAM_IN ||
384 20974 : fpmode == FUNC_PARAM_VARIADIC) &&
385 20910 : (prevfpmode == FUNC_PARAM_OUT ||
386 : prevfpmode == FUNC_PARAM_TABLE))
387 64 : continue;
388 124944 : if ((prevfpmode == FUNC_PARAM_IN ||
389 41614 : prevfpmode == FUNC_PARAM_VARIADIC) &&
390 21412 : (fpmode == FUNC_PARAM_OUT ||
391 : fpmode == FUNC_PARAM_TABLE))
392 20660 : continue;
393 104284 : if (prevfp->name && prevfp->name[0] &&
394 104254 : 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 31376 : paramNames[i] = CStringGetTextDatum(fp->name);
403 31376 : have_names = true;
404 : }
405 :
406 53882 : if (inParameterNames_list)
407 53258 : *inParameterNames_list = lappend(*inParameterNames_list, makeString(fp->name ? fp->name : pstrdup("")));
408 :
409 53882 : if (fp->defexpr)
410 : {
411 : Node *def;
412 :
413 6180 : 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 6174 : def = transformExpr(pstate, fp->defexpr,
420 : EXPR_KIND_FUNCTION_DEFAULT);
421 6174 : def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
422 6174 : 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 12348 : if (pstate->p_rtable != NIL ||
429 6174 : 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 6174 : *parameterDefaults = lappend(*parameterDefaults, def);
450 6174 : have_defaults = true;
451 : }
452 : else
453 : {
454 47702 : 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 47696 : 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 53864 : i++;
473 : }
474 :
475 : /* Now construct the proper outputs as needed */
476 25042 : *parameterTypes = buildoidvector(inTypes, inCount);
477 :
478 25042 : if (outCount > 0 || varCount > 0)
479 : {
480 2630 : *allParameterTypes = construct_array_builtin(allTypes, parameterCount, OIDOID);
481 2630 : *parameterModes = construct_array_builtin(paramModes, parameterCount, CHAROID);
482 2630 : if (outCount > 1)
483 2262 : *requiredResultType = RECORDOID;
484 : /* otherwise we set requiredResultType correctly above */
485 : }
486 : else
487 : {
488 22412 : *allParameterTypes = NULL;
489 22412 : *parameterModes = NULL;
490 : }
491 :
492 25042 : if (have_names)
493 : {
494 39986 : for (i = 0; i < parameterCount; i++)
495 : {
496 31584 : if (paramNames[i] == PointerGetDatum(NULL))
497 262 : paramNames[i] = CStringGetTextDatum("");
498 : }
499 8402 : *parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
500 : }
501 : else
502 16640 : *parameterNames = NULL;
503 25042 : }
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 45466 : 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 45466 : if (strcmp(defel->defname, "volatility") == 0)
529 : {
530 13278 : if (is_procedure)
531 0 : goto procedure_error;
532 13278 : if (*volatility_item)
533 0 : errorConflictingDefElem(defel, pstate);
534 :
535 13278 : *volatility_item = defel;
536 : }
537 32188 : else if (strcmp(defel->defname, "strict") == 0)
538 : {
539 13900 : if (is_procedure)
540 12 : goto procedure_error;
541 13888 : if (*strict_item)
542 0 : errorConflictingDefElem(defel, pstate);
543 :
544 13888 : *strict_item = defel;
545 : }
546 18288 : else if (strcmp(defel->defname, "security") == 0)
547 : {
548 76 : if (*security_item)
549 0 : errorConflictingDefElem(defel, pstate);
550 :
551 76 : *security_item = defel;
552 : }
553 18212 : else if (strcmp(defel->defname, "leakproof") == 0)
554 : {
555 62 : if (is_procedure)
556 0 : goto procedure_error;
557 62 : if (*leakproof_item)
558 0 : errorConflictingDefElem(defel, pstate);
559 :
560 62 : *leakproof_item = defel;
561 : }
562 18150 : else if (strcmp(defel->defname, "set") == 0)
563 : {
564 160 : *set_items = lappend(*set_items, defel->arg);
565 : }
566 17990 : else if (strcmp(defel->defname, "cost") == 0)
567 : {
568 4270 : if (is_procedure)
569 0 : goto procedure_error;
570 4270 : if (*cost_item)
571 0 : errorConflictingDefElem(defel, pstate);
572 :
573 4270 : *cost_item = defel;
574 : }
575 13720 : else if (strcmp(defel->defname, "rows") == 0)
576 : {
577 588 : if (is_procedure)
578 0 : goto procedure_error;
579 588 : if (*rows_item)
580 0 : errorConflictingDefElem(defel, pstate);
581 :
582 588 : *rows_item = defel;
583 : }
584 13132 : else if (strcmp(defel->defname, "support") == 0)
585 : {
586 116 : if (is_procedure)
587 0 : goto procedure_error;
588 116 : if (*support_item)
589 0 : errorConflictingDefElem(defel, pstate);
590 :
591 116 : *support_item = defel;
592 : }
593 13016 : else if (strcmp(defel->defname, "parallel") == 0)
594 : {
595 13016 : if (is_procedure)
596 0 : goto procedure_error;
597 13016 : if (*parallel_item)
598 0 : errorConflictingDefElem(defel, pstate);
599 :
600 13016 : *parallel_item = defel;
601 : }
602 : else
603 0 : return false;
604 :
605 : /* Recognized an option */
606 45454 : 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 13278 : interpret_func_volatility(DefElem *defel)
618 : {
619 13278 : char *str = strVal(defel->arg);
620 :
621 13278 : if (strcmp(str, "immutable") == 0)
622 9166 : return PROVOLATILE_IMMUTABLE;
623 4112 : else if (strcmp(str, "stable") == 0)
624 2486 : return PROVOLATILE_STABLE;
625 1626 : else if (strcmp(str, "volatile") == 0)
626 1626 : 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 13016 : interpret_func_parallel(DefElem *defel)
636 : {
637 13016 : char *str = strVal(defel->arg);
638 :
639 13016 : if (strcmp(str, "safe") == 0)
640 11620 : return PROPARALLEL_SAFE;
641 1396 : else if (strcmp(str, "unsafe") == 0)
642 432 : return PROPARALLEL_UNSAFE;
643 964 : else if (strcmp(str, "restricted") == 0)
644 964 : 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 120 : update_proconfig_value(ArrayType *a, List *set_items)
661 : {
662 : ListCell *l;
663 :
664 280 : foreach(l, set_items)
665 : {
666 160 : VariableSetStmt *sstmt = lfirst_node(VariableSetStmt, l);
667 :
668 160 : if (sstmt->kind == VAR_RESET_ALL)
669 12 : a = NULL;
670 : else
671 : {
672 148 : char *valuestr = ExtractSetVariableArgs(sstmt);
673 :
674 148 : if (valuestr)
675 148 : a = GUCArrayAdd(a, sstmt->name, valuestr);
676 : else /* RESET */
677 0 : a = GUCArrayDelete(a, sstmt->name);
678 : }
679 : }
680 :
681 120 : return a;
682 : }
683 :
684 : static Oid
685 116 : interpret_func_support(DefElem *defel)
686 : {
687 116 : 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 116 : argList[0] = INTERNALOID;
696 :
697 116 : procOid = LookupFuncName(procName, 1, argList, true);
698 116 : 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 116 : 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 116 : if (!superuser())
716 0 : ereport(ERROR,
717 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
718 : errmsg("must be superuser to specify a support function")));
719 :
720 116 : 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 24496 : 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 24496 : DefElem *as_item = NULL;
748 24496 : DefElem *language_item = NULL;
749 24496 : DefElem *transform_item = NULL;
750 24496 : DefElem *windowfunc_item = NULL;
751 24496 : DefElem *volatility_item = NULL;
752 24496 : DefElem *strict_item = NULL;
753 24496 : DefElem *security_item = NULL;
754 24496 : DefElem *leakproof_item = NULL;
755 24496 : List *set_items = NIL;
756 24496 : DefElem *cost_item = NULL;
757 24496 : DefElem *rows_item = NULL;
758 24496 : DefElem *support_item = NULL;
759 24496 : DefElem *parallel_item = NULL;
760 :
761 112778 : foreach(option, options)
762 : {
763 88294 : DefElem *defel = (DefElem *) lfirst(option);
764 :
765 88294 : if (strcmp(defel->defname, "as") == 0)
766 : {
767 18920 : if (as_item)
768 0 : errorConflictingDefElem(defel, pstate);
769 18920 : as_item = defel;
770 : }
771 69374 : else if (strcmp(defel->defname, "language") == 0)
772 : {
773 24426 : if (language_item)
774 0 : errorConflictingDefElem(defel, pstate);
775 24426 : language_item = defel;
776 : }
777 44948 : 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 44830 : else if (strcmp(defel->defname, "window") == 0)
784 : {
785 22 : if (windowfunc_item)
786 0 : errorConflictingDefElem(defel, pstate);
787 22 : 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 16 : windowfunc_item = defel;
793 : }
794 44808 : 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 44802 : continue;
809 : }
810 : else
811 0 : elog(ERROR, "option \"%s\" not recognized",
812 : defel->defname);
813 : }
814 :
815 24484 : if (as_item)
816 18920 : *as = (List *) as_item->arg;
817 24484 : if (language_item)
818 24414 : *language = strVal(language_item->arg);
819 24484 : if (transform_item)
820 118 : *transform = transform_item->arg;
821 24484 : if (windowfunc_item)
822 16 : *windowfunc_p = boolVal(windowfunc_item->arg);
823 24484 : if (volatility_item)
824 13240 : *volatility_p = interpret_func_volatility(volatility_item);
825 24484 : if (strict_item)
826 13864 : *strict_p = boolVal(strict_item->arg);
827 24484 : if (security_item)
828 52 : *security_definer = boolVal(security_item->arg);
829 24484 : if (leakproof_item)
830 38 : *leakproof_p = boolVal(leakproof_item->arg);
831 24484 : if (set_items)
832 102 : *proconfig = update_proconfig_value(NULL, set_items);
833 24484 : if (cost_item)
834 : {
835 4258 : *procost = defGetNumeric(cost_item);
836 4258 : if (*procost <= 0)
837 0 : ereport(ERROR,
838 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
839 : errmsg("COST must be positive")));
840 : }
841 24484 : if (rows_item)
842 : {
843 588 : *prorows = defGetNumeric(rows_item);
844 588 : if (*prorows <= 0)
845 0 : ereport(ERROR,
846 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
847 : errmsg("ROWS must be positive")));
848 : }
849 24484 : if (support_item)
850 110 : *prosupport = interpret_func_support(support_item);
851 24484 : if (parallel_item)
852 12510 : *parallel_p = interpret_func_parallel(parallel_item);
853 24484 : }
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 24398 : 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 24398 : if (!sql_body_in && !as)
874 0 : ereport(ERROR,
875 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
876 : errmsg("no function body specified")));
877 :
878 24398 : if (sql_body_in && as)
879 6 : ereport(ERROR,
880 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
881 : errmsg("duplicate function body specified")));
882 :
883 24392 : 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 24392 : *sql_body_out = NULL;
889 :
890 24392 : 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 5706 : *probin_str_p = strVal(linitial(as));
901 5706 : if (list_length(as) == 1)
902 2592 : *prosrc_str_p = funcname;
903 : else
904 : {
905 3114 : *prosrc_str_p = strVal(lsecond(as));
906 3114 : if (strcmp(*prosrc_str_p, "-") == 0)
907 0 : *prosrc_str_p = funcname;
908 : }
909 : }
910 18686 : else if (sql_body_in)
911 : {
912 : SQLFunctionParseInfoPtr pinfo;
913 :
914 5564 : pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
915 :
916 5564 : pinfo->fname = funcname;
917 5564 : pinfo->nargs = list_length(parameterTypes);
918 5564 : pinfo->argtypes = (Oid *) palloc(pinfo->nargs * sizeof(Oid));
919 5564 : pinfo->argnames = (char **) palloc(pinfo->nargs * sizeof(char *));
920 16834 : for (int i = 0; i < list_length(parameterTypes); i++)
921 : {
922 11276 : char *s = strVal(list_nth(inParameterNames, i));
923 :
924 11276 : pinfo->argtypes[i] = list_nth_oid(parameterTypes, i);
925 11276 : 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 11270 : if (s[0] != '\0')
931 1854 : pinfo->argnames[i] = s;
932 : else
933 9416 : pinfo->argnames[i] = NULL;
934 : }
935 :
936 5558 : if (IsA(sql_body_in, List))
937 : {
938 792 : List *stmts = linitial_node(List, castNode(List, sql_body_in));
939 : ListCell *lc;
940 792 : List *transformed_stmts = NIL;
941 :
942 1574 : foreach(lc, stmts)
943 : {
944 788 : Node *stmt = lfirst(lc);
945 : Query *q;
946 788 : ParseState *pstate = make_parsestate(NULL);
947 :
948 788 : pstate->p_sourcetext = queryString;
949 788 : sql_fn_parser_setup(pstate, pinfo);
950 788 : q = transformStmt(pstate, stmt);
951 788 : 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 782 : transformed_stmts = lappend(transformed_stmts, q);
957 782 : free_parsestate(pstate);
958 : }
959 :
960 786 : *sql_body_out = (Node *) list_make1(transformed_stmts);
961 : }
962 : else
963 : {
964 : Query *q;
965 4766 : ParseState *pstate = make_parsestate(NULL);
966 :
967 4766 : pstate->p_sourcetext = queryString;
968 4766 : sql_fn_parser_setup(pstate, pinfo);
969 4766 : q = transformStmt(pstate, sql_body_in);
970 4760 : 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 4760 : free_parsestate(pstate);
976 :
977 4760 : *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 5546 : *prosrc_str_p = pstrdup("");
988 :
989 : /* But we definitely don't need probin. */
990 5546 : *probin_str_p = NULL;
991 : }
992 : else
993 : {
994 : /* Everything else wants the given string in prosrc. */
995 13122 : *prosrc_str_p = strVal(linitial(as));
996 13122 : *probin_str_p = NULL;
997 :
998 13122 : 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 13116 : 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 4198 : if (strlen(*prosrc_str_p) == 0)
1015 0 : *prosrc_str_p = funcname;
1016 : }
1017 : }
1018 24368 : }
1019 :
1020 :
1021 : /*
1022 : * CreateFunction
1023 : * Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement.
1024 : */
1025 : ObjectAddress
1026 24496 : 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 24496 : Node *transformDefElem = NULL;
1037 : char *funcname;
1038 : Oid namespaceId;
1039 : AclResult aclresult;
1040 : oidvector *parameterTypes;
1041 24496 : List *parameterTypes_list = NIL;
1042 : ArrayType *allParameterTypes;
1043 : ArrayType *parameterModes;
1044 : ArrayType *parameterNames;
1045 24496 : List *inParameterNames_list = NIL;
1046 : List *parameterDefaults;
1047 : Oid variadicArgType;
1048 24496 : List *trftypes_list = NIL;
1049 24496 : List *trfoids_list = NIL;
1050 : ArrayType *trftypes;
1051 : Oid requiredResultType;
1052 : bool isWindowFunc,
1053 : isStrict,
1054 : security,
1055 : isLeakProof;
1056 : char volatility;
1057 : ArrayType *proconfig;
1058 : float4 procost;
1059 : float4 prorows;
1060 : Oid prosupport;
1061 : HeapTuple languageTuple;
1062 : Form_pg_language languageStruct;
1063 : List *as_clause;
1064 : char parallel;
1065 :
1066 : /* Convert list of names to a name and namespace */
1067 24496 : namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
1068 : &funcname);
1069 :
1070 : /* Check we have creation rights in target namespace */
1071 24496 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
1072 24496 : if (aclresult != ACLCHECK_OK)
1073 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
1074 0 : get_namespace_name(namespaceId));
1075 :
1076 : /* Set default attributes */
1077 24496 : as_clause = NIL;
1078 24496 : language = NULL;
1079 24496 : isWindowFunc = false;
1080 24496 : isStrict = false;
1081 24496 : security = false;
1082 24496 : isLeakProof = false;
1083 24496 : volatility = PROVOLATILE_VOLATILE;
1084 24496 : proconfig = NULL;
1085 24496 : procost = -1; /* indicates not set */
1086 24496 : prorows = -1; /* indicates not set */
1087 24496 : prosupport = InvalidOid;
1088 24496 : parallel = PROPARALLEL_UNSAFE;
1089 :
1090 : /* Extract non-default attributes from stmt->options list */
1091 24496 : compute_function_attributes(pstate,
1092 24496 : stmt->is_procedure,
1093 : stmt->options,
1094 : &as_clause, &language, &transformDefElem,
1095 : &isWindowFunc, &volatility,
1096 : &isStrict, &security, &isLeakProof,
1097 : &proconfig, &procost, &prorows,
1098 : &prosupport, ¶llel);
1099 :
1100 24484 : if (!language)
1101 : {
1102 70 : if (stmt->sql_body)
1103 70 : language = "sql";
1104 : else
1105 0 : ereport(ERROR,
1106 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1107 : errmsg("no language specified")));
1108 : }
1109 :
1110 : /* Look up the language and validate permissions */
1111 24484 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
1112 24484 : if (!HeapTupleIsValid(languageTuple))
1113 0 : ereport(ERROR,
1114 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1115 : errmsg("language \"%s\" does not exist", language),
1116 : (extension_file_exists(language) ?
1117 : errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
1118 :
1119 24484 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
1120 24484 : languageOid = languageStruct->oid;
1121 :
1122 24484 : if (languageStruct->lanpltrusted)
1123 : {
1124 : /* if trusted language, need USAGE privilege */
1125 14032 : aclresult = object_aclcheck(LanguageRelationId, languageOid, GetUserId(), ACL_USAGE);
1126 14032 : if (aclresult != ACLCHECK_OK)
1127 8 : aclcheck_error(aclresult, OBJECT_LANGUAGE,
1128 8 : NameStr(languageStruct->lanname));
1129 : }
1130 : else
1131 : {
1132 : /* if untrusted language, must be superuser */
1133 10452 : if (!superuser())
1134 0 : aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
1135 0 : NameStr(languageStruct->lanname));
1136 : }
1137 :
1138 24476 : languageValidator = languageStruct->lanvalidator;
1139 :
1140 24476 : ReleaseSysCache(languageTuple);
1141 :
1142 : /*
1143 : * Only superuser is allowed to create leakproof functions because
1144 : * leakproof functions can see tuples which have not yet been filtered out
1145 : * by security barrier views or row-level security policies.
1146 : */
1147 24476 : if (isLeakProof && !superuser())
1148 6 : ereport(ERROR,
1149 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1150 : errmsg("only superuser can define a leakproof function")));
1151 :
1152 24470 : if (transformDefElem)
1153 : {
1154 : ListCell *lc;
1155 :
1156 240 : foreach(lc, castNode(List, transformDefElem))
1157 : {
1158 122 : Oid typeid = typenameTypeId(NULL,
1159 122 : lfirst_node(TypeName, lc));
1160 122 : Oid elt = get_base_element_type(typeid);
1161 : Oid transformid;
1162 :
1163 122 : typeid = elt ? elt : typeid;
1164 122 : transformid = get_transform_oid(typeid, languageOid, false);
1165 122 : trftypes_list = lappend_oid(trftypes_list, typeid);
1166 122 : trfoids_list = lappend_oid(trfoids_list, transformid);
1167 : }
1168 : }
1169 :
1170 : /*
1171 : * Convert remaining parameters of CREATE to form wanted by
1172 : * ProcedureCreate.
1173 : */
1174 24470 : interpret_function_parameter_list(pstate,
1175 : stmt->parameters,
1176 : languageOid,
1177 24470 : stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
1178 : ¶meterTypes,
1179 : ¶meterTypes_list,
1180 : &allParameterTypes,
1181 : ¶meterModes,
1182 : ¶meterNames,
1183 : &inParameterNames_list,
1184 : ¶meterDefaults,
1185 : &variadicArgType,
1186 : &requiredResultType);
1187 :
1188 24416 : if (stmt->is_procedure)
1189 : {
1190 : Assert(!stmt->returnType);
1191 366 : prorettype = requiredResultType ? requiredResultType : VOIDOID;
1192 366 : returnsSet = false;
1193 : }
1194 24050 : else if (stmt->returnType)
1195 : {
1196 : /* explicit RETURNS clause */
1197 23562 : compute_return_type(stmt->returnType, languageOid,
1198 : &prorettype, &returnsSet);
1199 23556 : if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1200 12 : ereport(ERROR,
1201 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1202 : errmsg("function result type must be %s because of OUT parameters",
1203 : format_type_be(requiredResultType))));
1204 : }
1205 488 : else if (OidIsValid(requiredResultType))
1206 : {
1207 : /* default RETURNS clause from OUT parameters */
1208 488 : prorettype = requiredResultType;
1209 488 : returnsSet = false;
1210 : }
1211 : else
1212 : {
1213 0 : ereport(ERROR,
1214 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1215 : errmsg("function result type must be specified")));
1216 : /* Alternative possibility: default to RETURNS VOID */
1217 : prorettype = VOIDOID;
1218 : returnsSet = false;
1219 : }
1220 :
1221 24398 : if (trftypes_list != NIL)
1222 : {
1223 : ListCell *lc;
1224 : Datum *arr;
1225 : int i;
1226 :
1227 118 : arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1228 118 : i = 0;
1229 240 : foreach(lc, trftypes_list)
1230 122 : arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1231 118 : trftypes = construct_array_builtin(arr, list_length(trftypes_list), OIDOID);
1232 : }
1233 : else
1234 : {
1235 : /* store SQL NULL instead of empty array */
1236 24280 : trftypes = NULL;
1237 : }
1238 :
1239 24398 : interpret_AS_clause(languageOid, language, funcname, as_clause, stmt->sql_body,
1240 : parameterTypes_list, inParameterNames_list,
1241 : &prosrc_str, &probin_str, &prosqlbody,
1242 : pstate->p_sourcetext);
1243 :
1244 : /*
1245 : * Set default values for COST and ROWS depending on other parameters;
1246 : * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1247 : * values, keep it in sync if you change them.
1248 : */
1249 24368 : if (procost < 0)
1250 : {
1251 : /* SQL and PL-language functions are assumed more expensive */
1252 20110 : if (languageOid == INTERNALlanguageId ||
1253 : languageOid == ClanguageId)
1254 9434 : procost = 1;
1255 : else
1256 10676 : procost = 100;
1257 : }
1258 24368 : if (prorows < 0)
1259 : {
1260 23780 : if (returnsSet)
1261 1916 : prorows = 1000;
1262 : else
1263 21864 : prorows = 0; /* dummy value if not returnsSet */
1264 : }
1265 588 : else if (!returnsSet)
1266 0 : ereport(ERROR,
1267 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1268 : errmsg("ROWS is not applicable when function does not return a set")));
1269 :
1270 : /*
1271 : * And now that we have all the parameters, and know we're permitted to do
1272 : * so, go ahead and create the function.
1273 : */
1274 48736 : return ProcedureCreate(funcname,
1275 : namespaceId,
1276 24368 : stmt->replace,
1277 : returnsSet,
1278 : prorettype,
1279 : GetUserId(),
1280 : languageOid,
1281 : languageValidator,
1282 : prosrc_str, /* converted to text later */
1283 : probin_str, /* converted to text later */
1284 : prosqlbody,
1285 24368 : stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
1286 : security,
1287 : isLeakProof,
1288 : isStrict,
1289 : volatility,
1290 : parallel,
1291 : parameterTypes,
1292 : PointerGetDatum(allParameterTypes),
1293 : PointerGetDatum(parameterModes),
1294 : PointerGetDatum(parameterNames),
1295 : parameterDefaults,
1296 : PointerGetDatum(trftypes),
1297 : trfoids_list,
1298 : PointerGetDatum(proconfig),
1299 : prosupport,
1300 : procost,
1301 : prorows);
1302 : }
1303 :
1304 : /*
1305 : * Guts of function deletion.
1306 : *
1307 : * Note: this is also used for aggregate deletion, since the OIDs of
1308 : * both functions and aggregates point to pg_proc.
1309 : */
1310 : void
1311 7024 : RemoveFunctionById(Oid funcOid)
1312 : {
1313 : Relation relation;
1314 : HeapTuple tup;
1315 : char prokind;
1316 :
1317 : /*
1318 : * Delete the pg_proc tuple.
1319 : */
1320 7024 : relation = table_open(ProcedureRelationId, RowExclusiveLock);
1321 :
1322 7024 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1323 7024 : if (!HeapTupleIsValid(tup)) /* should not happen */
1324 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1325 :
1326 7024 : prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
1327 :
1328 7024 : CatalogTupleDelete(relation, &tup->t_self);
1329 :
1330 7024 : ReleaseSysCache(tup);
1331 :
1332 7024 : table_close(relation, RowExclusiveLock);
1333 :
1334 7024 : pgstat_drop_function(funcOid);
1335 :
1336 : /*
1337 : * If there's a pg_aggregate tuple, delete that too.
1338 : */
1339 7024 : if (prokind == PROKIND_AGGREGATE)
1340 : {
1341 120 : relation = table_open(AggregateRelationId, RowExclusiveLock);
1342 :
1343 120 : tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1344 120 : if (!HeapTupleIsValid(tup)) /* should not happen */
1345 0 : elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1346 :
1347 120 : CatalogTupleDelete(relation, &tup->t_self);
1348 :
1349 120 : ReleaseSysCache(tup);
1350 :
1351 120 : table_close(relation, RowExclusiveLock);
1352 : }
1353 7024 : }
1354 :
1355 : /*
1356 : * Implements the ALTER FUNCTION utility command (except for the
1357 : * RENAME and OWNER clauses, which are handled as part of the generic
1358 : * ALTER framework).
1359 : */
1360 : ObjectAddress
1361 672 : AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
1362 : {
1363 : HeapTuple tup;
1364 : Oid funcOid;
1365 : Form_pg_proc procForm;
1366 : bool is_procedure;
1367 : Relation rel;
1368 : ListCell *l;
1369 672 : DefElem *volatility_item = NULL;
1370 672 : DefElem *strict_item = NULL;
1371 672 : DefElem *security_def_item = NULL;
1372 672 : DefElem *leakproof_item = NULL;
1373 672 : List *set_items = NIL;
1374 672 : DefElem *cost_item = NULL;
1375 672 : DefElem *rows_item = NULL;
1376 672 : DefElem *support_item = NULL;
1377 672 : DefElem *parallel_item = NULL;
1378 : ObjectAddress address;
1379 :
1380 672 : rel = table_open(ProcedureRelationId, RowExclusiveLock);
1381 :
1382 672 : funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1383 :
1384 654 : ObjectAddressSet(address, ProcedureRelationId, funcOid);
1385 :
1386 654 : tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1387 654 : if (!HeapTupleIsValid(tup)) /* should not happen */
1388 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1389 :
1390 654 : procForm = (Form_pg_proc) GETSTRUCT(tup);
1391 :
1392 : /* Permission check: must own function */
1393 654 : if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
1394 0 : aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
1395 0 : NameListToString(stmt->func->objname));
1396 :
1397 654 : if (procForm->prokind == PROKIND_AGGREGATE)
1398 0 : ereport(ERROR,
1399 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1400 : errmsg("\"%s\" is an aggregate function",
1401 : NameListToString(stmt->func->objname))));
1402 :
1403 654 : is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1404 :
1405 : /* Examine requested actions. */
1406 1306 : foreach(l, stmt->actions)
1407 : {
1408 658 : DefElem *defel = (DefElem *) lfirst(l);
1409 :
1410 658 : if (compute_common_attribute(pstate,
1411 : is_procedure,
1412 : defel,
1413 : &volatility_item,
1414 : &strict_item,
1415 : &security_def_item,
1416 : &leakproof_item,
1417 : &set_items,
1418 : &cost_item,
1419 : &rows_item,
1420 : &support_item,
1421 652 : ¶llel_item) == false)
1422 0 : elog(ERROR, "option \"%s\" not recognized", defel->defname);
1423 : }
1424 :
1425 648 : if (volatility_item)
1426 38 : procForm->provolatile = interpret_func_volatility(volatility_item);
1427 648 : if (strict_item)
1428 24 : procForm->proisstrict = boolVal(strict_item->arg);
1429 648 : if (security_def_item)
1430 24 : procForm->prosecdef = boolVal(security_def_item->arg);
1431 648 : if (leakproof_item)
1432 : {
1433 24 : procForm->proleakproof = boolVal(leakproof_item->arg);
1434 24 : if (procForm->proleakproof && !superuser())
1435 6 : ereport(ERROR,
1436 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1437 : errmsg("only superuser can define a leakproof function")));
1438 : }
1439 642 : if (cost_item)
1440 : {
1441 12 : procForm->procost = defGetNumeric(cost_item);
1442 12 : if (procForm->procost <= 0)
1443 0 : ereport(ERROR,
1444 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1445 : errmsg("COST must be positive")));
1446 : }
1447 642 : if (rows_item)
1448 : {
1449 0 : procForm->prorows = defGetNumeric(rows_item);
1450 0 : if (procForm->prorows <= 0)
1451 0 : ereport(ERROR,
1452 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1453 : errmsg("ROWS must be positive")));
1454 0 : if (!procForm->proretset)
1455 0 : ereport(ERROR,
1456 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1457 : errmsg("ROWS is not applicable when function does not return a set")));
1458 : }
1459 642 : if (support_item)
1460 : {
1461 : /* interpret_func_support handles the privilege check */
1462 6 : Oid newsupport = interpret_func_support(support_item);
1463 :
1464 : /* Add or replace dependency on support function */
1465 6 : if (OidIsValid(procForm->prosupport))
1466 : {
1467 0 : if (changeDependencyFor(ProcedureRelationId, funcOid,
1468 : ProcedureRelationId, procForm->prosupport,
1469 : newsupport) != 1)
1470 0 : elog(ERROR, "could not change support dependency for function %s",
1471 : get_func_name(funcOid));
1472 : }
1473 : else
1474 : {
1475 : ObjectAddress referenced;
1476 :
1477 6 : referenced.classId = ProcedureRelationId;
1478 6 : referenced.objectId = newsupport;
1479 6 : referenced.objectSubId = 0;
1480 6 : recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
1481 : }
1482 :
1483 6 : procForm->prosupport = newsupport;
1484 : }
1485 642 : if (parallel_item)
1486 506 : procForm->proparallel = interpret_func_parallel(parallel_item);
1487 642 : if (set_items)
1488 : {
1489 : Datum datum;
1490 : bool isnull;
1491 : ArrayType *a;
1492 : Datum repl_val[Natts_pg_proc];
1493 : bool repl_null[Natts_pg_proc];
1494 : bool repl_repl[Natts_pg_proc];
1495 :
1496 : /* extract existing proconfig setting */
1497 18 : datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1498 18 : a = isnull ? NULL : DatumGetArrayTypeP(datum);
1499 :
1500 : /* update according to each SET or RESET item, left to right */
1501 18 : a = update_proconfig_value(a, set_items);
1502 :
1503 : /* update the tuple */
1504 18 : memset(repl_repl, false, sizeof(repl_repl));
1505 18 : repl_repl[Anum_pg_proc_proconfig - 1] = true;
1506 :
1507 18 : if (a == NULL)
1508 : {
1509 12 : repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1510 12 : repl_null[Anum_pg_proc_proconfig - 1] = true;
1511 : }
1512 : else
1513 : {
1514 6 : repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1515 6 : repl_null[Anum_pg_proc_proconfig - 1] = false;
1516 : }
1517 :
1518 18 : tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1519 : repl_val, repl_null, repl_repl);
1520 : }
1521 : /* DO NOT put more touches of procForm below here; it's now dangling. */
1522 :
1523 : /* Do the update */
1524 642 : CatalogTupleUpdate(rel, &tup->t_self, tup);
1525 :
1526 642 : InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1527 :
1528 642 : table_close(rel, NoLock);
1529 642 : heap_freetuple(tup);
1530 :
1531 642 : return address;
1532 : }
1533 :
1534 :
1535 : /*
1536 : * CREATE CAST
1537 : */
1538 : ObjectAddress
1539 290 : CreateCast(CreateCastStmt *stmt)
1540 : {
1541 : Oid sourcetypeid;
1542 : Oid targettypeid;
1543 : char sourcetyptype;
1544 : char targettyptype;
1545 : Oid funcid;
1546 290 : Oid incastid = InvalidOid;
1547 290 : Oid outcastid = InvalidOid;
1548 : int nargs;
1549 : char castcontext;
1550 : char castmethod;
1551 : HeapTuple tuple;
1552 : AclResult aclresult;
1553 : ObjectAddress myself;
1554 :
1555 290 : sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
1556 290 : targettypeid = typenameTypeId(NULL, stmt->targettype);
1557 290 : sourcetyptype = get_typtype(sourcetypeid);
1558 290 : targettyptype = get_typtype(targettypeid);
1559 :
1560 : /* No pseudo-types allowed */
1561 290 : if (sourcetyptype == TYPTYPE_PSEUDO)
1562 0 : ereport(ERROR,
1563 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1564 : errmsg("source data type %s is a pseudo-type",
1565 : TypeNameToString(stmt->sourcetype))));
1566 :
1567 290 : if (targettyptype == TYPTYPE_PSEUDO)
1568 0 : ereport(ERROR,
1569 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1570 : errmsg("target data type %s is a pseudo-type",
1571 : TypeNameToString(stmt->targettype))));
1572 :
1573 : /* Permission check */
1574 290 : if (!object_ownercheck(TypeRelationId, sourcetypeid, GetUserId())
1575 12 : && !object_ownercheck(TypeRelationId, targettypeid, GetUserId()))
1576 0 : ereport(ERROR,
1577 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1578 : errmsg("must be owner of type %s or type %s",
1579 : format_type_be(sourcetypeid),
1580 : format_type_be(targettypeid))));
1581 :
1582 290 : aclresult = object_aclcheck(TypeRelationId, sourcetypeid, GetUserId(), ACL_USAGE);
1583 290 : if (aclresult != ACLCHECK_OK)
1584 6 : aclcheck_error_type(aclresult, sourcetypeid);
1585 :
1586 284 : aclresult = object_aclcheck(TypeRelationId, targettypeid, GetUserId(), ACL_USAGE);
1587 284 : if (aclresult != ACLCHECK_OK)
1588 0 : aclcheck_error_type(aclresult, targettypeid);
1589 :
1590 : /* Domains are allowed for historical reasons, but we warn */
1591 284 : if (sourcetyptype == TYPTYPE_DOMAIN)
1592 6 : ereport(WARNING,
1593 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1594 : errmsg("cast will be ignored because the source data type is a domain")));
1595 :
1596 278 : else if (targettyptype == TYPTYPE_DOMAIN)
1597 0 : ereport(WARNING,
1598 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1599 : errmsg("cast will be ignored because the target data type is a domain")));
1600 :
1601 : /* Determine the cast method */
1602 284 : if (stmt->func != NULL)
1603 104 : castmethod = COERCION_METHOD_FUNCTION;
1604 180 : else if (stmt->inout)
1605 8 : castmethod = COERCION_METHOD_INOUT;
1606 : else
1607 172 : castmethod = COERCION_METHOD_BINARY;
1608 :
1609 284 : if (castmethod == COERCION_METHOD_FUNCTION)
1610 : {
1611 : Form_pg_proc procstruct;
1612 :
1613 104 : funcid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->func, false);
1614 :
1615 104 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1616 104 : if (!HeapTupleIsValid(tuple))
1617 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1618 :
1619 104 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1620 104 : nargs = procstruct->pronargs;
1621 104 : if (nargs < 1 || nargs > 3)
1622 0 : ereport(ERROR,
1623 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1624 : errmsg("cast function must take one to three arguments")));
1625 104 : if (!IsBinaryCoercibleWithCast(sourcetypeid,
1626 : procstruct->proargtypes.values[0],
1627 : &incastid))
1628 0 : ereport(ERROR,
1629 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1630 : errmsg("argument of cast function must match or be binary-coercible from source data type")));
1631 104 : if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1632 0 : ereport(ERROR,
1633 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1634 : errmsg("second argument of cast function must be type %s",
1635 : "integer")));
1636 104 : if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1637 0 : ereport(ERROR,
1638 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1639 : errmsg("third argument of cast function must be type %s",
1640 : "boolean")));
1641 104 : if (!IsBinaryCoercibleWithCast(procstruct->prorettype,
1642 : targettypeid,
1643 : &outcastid))
1644 0 : ereport(ERROR,
1645 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1646 : errmsg("return data type of cast function must match or be binary-coercible to target data type")));
1647 :
1648 : /*
1649 : * Restricting the volatility of a cast function may or may not be a
1650 : * good idea in the abstract, but it definitely breaks many old
1651 : * user-defined types. Disable this check --- tgl 2/1/03
1652 : */
1653 : #ifdef NOT_USED
1654 : if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1655 : ereport(ERROR,
1656 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1657 : errmsg("cast function must not be volatile")));
1658 : #endif
1659 104 : if (procstruct->prokind != PROKIND_FUNCTION)
1660 0 : ereport(ERROR,
1661 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1662 : errmsg("cast function must be a normal function")));
1663 104 : if (procstruct->proretset)
1664 0 : ereport(ERROR,
1665 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1666 : errmsg("cast function must not return a set")));
1667 :
1668 104 : ReleaseSysCache(tuple);
1669 : }
1670 : else
1671 : {
1672 180 : funcid = InvalidOid;
1673 180 : nargs = 0;
1674 : }
1675 :
1676 284 : if (castmethod == COERCION_METHOD_BINARY)
1677 : {
1678 : int16 typ1len;
1679 : int16 typ2len;
1680 : bool typ1byval;
1681 : bool typ2byval;
1682 : char typ1align;
1683 : char typ2align;
1684 :
1685 : /*
1686 : * Must be superuser to create binary-compatible casts, since
1687 : * erroneous casts can easily crash the backend.
1688 : */
1689 172 : if (!superuser())
1690 0 : ereport(ERROR,
1691 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1692 : errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1693 :
1694 : /*
1695 : * Also, insist that the types match as to size, alignment, and
1696 : * pass-by-value attributes; this provides at least a crude check that
1697 : * they have similar representations. A pair of types that fail this
1698 : * test should certainly not be equated.
1699 : */
1700 172 : get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1701 172 : get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1702 172 : if (typ1len != typ2len ||
1703 172 : typ1byval != typ2byval ||
1704 172 : typ1align != typ2align)
1705 0 : ereport(ERROR,
1706 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1707 : errmsg("source and target data types are not physically compatible")));
1708 :
1709 : /*
1710 : * We know that composite, array, range and enum types are never
1711 : * binary-compatible with each other. They all have OIDs embedded in
1712 : * them.
1713 : *
1714 : * Theoretically you could build a user-defined base type that is
1715 : * binary-compatible with such a type. But we disallow it anyway, as
1716 : * in practice such a cast is surely a mistake. You can always work
1717 : * around that by writing a cast function.
1718 : *
1719 : * NOTE: if we ever have a kind of container type that doesn't need to
1720 : * be rejected for this reason, we'd likely need to recursively apply
1721 : * all of these same checks to the contained type(s).
1722 : */
1723 172 : if (sourcetyptype == TYPTYPE_COMPOSITE ||
1724 : targettyptype == TYPTYPE_COMPOSITE)
1725 0 : ereport(ERROR,
1726 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1727 : errmsg("composite data types are not binary-compatible")));
1728 :
1729 344 : if (OidIsValid(get_element_type(sourcetypeid)) ||
1730 172 : OidIsValid(get_element_type(targettypeid)))
1731 0 : ereport(ERROR,
1732 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1733 : errmsg("array data types are not binary-compatible")));
1734 :
1735 172 : if (sourcetyptype == TYPTYPE_RANGE ||
1736 172 : targettyptype == TYPTYPE_RANGE ||
1737 172 : sourcetyptype == TYPTYPE_MULTIRANGE ||
1738 : targettyptype == TYPTYPE_MULTIRANGE)
1739 0 : ereport(ERROR,
1740 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1741 : errmsg("range data types are not binary-compatible")));
1742 :
1743 172 : if (sourcetyptype == TYPTYPE_ENUM ||
1744 : targettyptype == TYPTYPE_ENUM)
1745 0 : ereport(ERROR,
1746 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1747 : errmsg("enum data types are not binary-compatible")));
1748 :
1749 : /*
1750 : * We also disallow creating binary-compatibility casts involving
1751 : * domains. Casting from a domain to its base type is already
1752 : * allowed, and casting the other way ought to go through domain
1753 : * coercion to permit constraint checking. Again, if you're intent on
1754 : * having your own semantics for that, create a no-op cast function.
1755 : *
1756 : * NOTE: if we were to relax this, the above checks for composites
1757 : * etc. would have to be modified to look through domains to their
1758 : * base types.
1759 : */
1760 172 : if (sourcetyptype == TYPTYPE_DOMAIN ||
1761 : targettyptype == TYPTYPE_DOMAIN)
1762 0 : ereport(ERROR,
1763 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1764 : errmsg("domain data types must not be marked binary-compatible")));
1765 : }
1766 :
1767 : /*
1768 : * Allow source and target types to be same only for length coercion
1769 : * functions. We assume a multi-arg function does length coercion.
1770 : */
1771 284 : if (sourcetypeid == targettypeid && nargs < 2)
1772 0 : ereport(ERROR,
1773 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1774 : errmsg("source data type and target data type are the same")));
1775 :
1776 : /* convert CoercionContext enum to char value for castcontext */
1777 284 : switch (stmt->context)
1778 : {
1779 40 : case COERCION_IMPLICIT:
1780 40 : castcontext = COERCION_CODE_IMPLICIT;
1781 40 : break;
1782 58 : case COERCION_ASSIGNMENT:
1783 58 : castcontext = COERCION_CODE_ASSIGNMENT;
1784 58 : break;
1785 : /* COERCION_PLPGSQL is intentionally not covered here */
1786 186 : case COERCION_EXPLICIT:
1787 186 : castcontext = COERCION_CODE_EXPLICIT;
1788 186 : break;
1789 0 : default:
1790 0 : elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1791 : castcontext = 0; /* keep compiler quiet */
1792 : break;
1793 : }
1794 :
1795 284 : myself = CastCreate(sourcetypeid, targettypeid, funcid, incastid, outcastid,
1796 : castcontext, castmethod, DEPENDENCY_NORMAL);
1797 284 : return myself;
1798 : }
1799 :
1800 :
1801 : static void
1802 84 : check_transform_function(Form_pg_proc procstruct)
1803 : {
1804 84 : if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1805 0 : ereport(ERROR,
1806 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1807 : errmsg("transform function must not be volatile")));
1808 84 : if (procstruct->prokind != PROKIND_FUNCTION)
1809 0 : ereport(ERROR,
1810 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1811 : errmsg("transform function must be a normal function")));
1812 84 : if (procstruct->proretset)
1813 0 : ereport(ERROR,
1814 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1815 : errmsg("transform function must not return a set")));
1816 84 : if (procstruct->pronargs != 1)
1817 0 : ereport(ERROR,
1818 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1819 : errmsg("transform function must take one argument")));
1820 84 : if (procstruct->proargtypes.values[0] != INTERNALOID)
1821 2 : ereport(ERROR,
1822 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1823 : errmsg("first argument of transform function must be type %s",
1824 : "internal")));
1825 82 : }
1826 :
1827 :
1828 : /*
1829 : * CREATE TRANSFORM
1830 : */
1831 : ObjectAddress
1832 52 : CreateTransform(CreateTransformStmt *stmt)
1833 : {
1834 : Oid typeid;
1835 : char typtype;
1836 : Oid langid;
1837 : Oid fromsqlfuncid;
1838 : Oid tosqlfuncid;
1839 : AclResult aclresult;
1840 : Form_pg_proc procstruct;
1841 : Datum values[Natts_pg_transform];
1842 52 : bool nulls[Natts_pg_transform] = {0};
1843 52 : bool replaces[Natts_pg_transform] = {0};
1844 : Oid transformid;
1845 : HeapTuple tuple;
1846 : HeapTuple newtuple;
1847 : Relation relation;
1848 : ObjectAddress myself,
1849 : referenced;
1850 : ObjectAddresses *addrs;
1851 : bool is_replace;
1852 :
1853 : /*
1854 : * Get the type
1855 : */
1856 52 : typeid = typenameTypeId(NULL, stmt->type_name);
1857 50 : typtype = get_typtype(typeid);
1858 :
1859 50 : if (typtype == TYPTYPE_PSEUDO)
1860 0 : ereport(ERROR,
1861 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1862 : errmsg("data type %s is a pseudo-type",
1863 : TypeNameToString(stmt->type_name))));
1864 :
1865 50 : if (typtype == TYPTYPE_DOMAIN)
1866 0 : ereport(ERROR,
1867 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1868 : errmsg("data type %s is a domain",
1869 : TypeNameToString(stmt->type_name))));
1870 :
1871 50 : if (!object_ownercheck(TypeRelationId, typeid, GetUserId()))
1872 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
1873 :
1874 50 : aclresult = object_aclcheck(TypeRelationId, typeid, GetUserId(), ACL_USAGE);
1875 50 : if (aclresult != ACLCHECK_OK)
1876 0 : aclcheck_error_type(aclresult, typeid);
1877 :
1878 : /*
1879 : * Get the language
1880 : */
1881 50 : langid = get_language_oid(stmt->lang, false);
1882 :
1883 48 : aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE);
1884 48 : if (aclresult != ACLCHECK_OK)
1885 0 : aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang);
1886 :
1887 : /*
1888 : * Get the functions
1889 : */
1890 48 : if (stmt->fromsql)
1891 : {
1892 46 : fromsqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->fromsql, false);
1893 :
1894 46 : if (!object_ownercheck(ProcedureRelationId, fromsqlfuncid, GetUserId()))
1895 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
1896 :
1897 46 : aclresult = object_aclcheck(ProcedureRelationId, fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1898 46 : if (aclresult != ACLCHECK_OK)
1899 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
1900 :
1901 46 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1902 46 : if (!HeapTupleIsValid(tuple))
1903 0 : elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1904 46 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1905 46 : if (procstruct->prorettype != INTERNALOID)
1906 2 : ereport(ERROR,
1907 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1908 : errmsg("return data type of FROM SQL function must be %s",
1909 : "internal")));
1910 44 : check_transform_function(procstruct);
1911 42 : ReleaseSysCache(tuple);
1912 : }
1913 : else
1914 2 : fromsqlfuncid = InvalidOid;
1915 :
1916 44 : if (stmt->tosql)
1917 : {
1918 40 : tosqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->tosql, false);
1919 :
1920 40 : if (!object_ownercheck(ProcedureRelationId, tosqlfuncid, GetUserId()))
1921 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
1922 :
1923 40 : aclresult = object_aclcheck(ProcedureRelationId, tosqlfuncid, GetUserId(), ACL_EXECUTE);
1924 40 : if (aclresult != ACLCHECK_OK)
1925 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
1926 :
1927 40 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1928 40 : if (!HeapTupleIsValid(tuple))
1929 0 : elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1930 40 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1931 40 : if (procstruct->prorettype != typeid)
1932 0 : ereport(ERROR,
1933 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1934 : errmsg("return data type of TO SQL function must be the transform data type")));
1935 40 : check_transform_function(procstruct);
1936 40 : ReleaseSysCache(tuple);
1937 : }
1938 : else
1939 4 : tosqlfuncid = InvalidOid;
1940 :
1941 : /*
1942 : * Ready to go
1943 : */
1944 44 : values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1945 44 : values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1946 44 : values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1947 44 : values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1948 :
1949 44 : relation = table_open(TransformRelationId, RowExclusiveLock);
1950 :
1951 44 : tuple = SearchSysCache2(TRFTYPELANG,
1952 : ObjectIdGetDatum(typeid),
1953 : ObjectIdGetDatum(langid));
1954 44 : if (HeapTupleIsValid(tuple))
1955 : {
1956 8 : Form_pg_transform form = (Form_pg_transform) GETSTRUCT(tuple);
1957 :
1958 8 : if (!stmt->replace)
1959 2 : ereport(ERROR,
1960 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1961 : errmsg("transform for type %s language \"%s\" already exists",
1962 : format_type_be(typeid),
1963 : stmt->lang)));
1964 :
1965 6 : replaces[Anum_pg_transform_trffromsql - 1] = true;
1966 6 : replaces[Anum_pg_transform_trftosql - 1] = true;
1967 :
1968 6 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1969 6 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1970 :
1971 6 : transformid = form->oid;
1972 6 : ReleaseSysCache(tuple);
1973 6 : is_replace = true;
1974 : }
1975 : else
1976 : {
1977 36 : transformid = GetNewOidWithIndex(relation, TransformOidIndexId,
1978 : Anum_pg_transform_oid);
1979 36 : values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid);
1980 36 : newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1981 36 : CatalogTupleInsert(relation, newtuple);
1982 36 : is_replace = false;
1983 : }
1984 :
1985 42 : if (is_replace)
1986 6 : deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1987 :
1988 42 : addrs = new_object_addresses();
1989 :
1990 : /* make dependency entries */
1991 42 : ObjectAddressSet(myself, TransformRelationId, transformid);
1992 :
1993 : /* dependency on language */
1994 42 : ObjectAddressSet(referenced, LanguageRelationId, langid);
1995 42 : add_exact_object_address(&referenced, addrs);
1996 :
1997 : /* dependency on type */
1998 42 : ObjectAddressSet(referenced, TypeRelationId, typeid);
1999 42 : add_exact_object_address(&referenced, addrs);
2000 :
2001 : /* dependencies on functions */
2002 42 : if (OidIsValid(fromsqlfuncid))
2003 : {
2004 40 : ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
2005 40 : add_exact_object_address(&referenced, addrs);
2006 : }
2007 42 : if (OidIsValid(tosqlfuncid))
2008 : {
2009 38 : ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
2010 38 : add_exact_object_address(&referenced, addrs);
2011 : }
2012 :
2013 42 : record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
2014 42 : free_object_addresses(addrs);
2015 :
2016 : /* dependency on extension */
2017 42 : recordDependencyOnCurrentExtension(&myself, is_replace);
2018 :
2019 : /* Post creation hook for new transform */
2020 42 : InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
2021 :
2022 42 : heap_freetuple(newtuple);
2023 :
2024 42 : table_close(relation, RowExclusiveLock);
2025 :
2026 42 : return myself;
2027 : }
2028 :
2029 :
2030 : /*
2031 : * get_transform_oid - given type OID and language OID, look up a transform OID
2032 : *
2033 : * If missing_ok is false, throw an error if the transform is not found. If
2034 : * true, just return InvalidOid.
2035 : */
2036 : Oid
2037 162 : get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
2038 : {
2039 : Oid oid;
2040 :
2041 162 : oid = GetSysCacheOid2(TRFTYPELANG, Anum_pg_transform_oid,
2042 : ObjectIdGetDatum(type_id),
2043 : ObjectIdGetDatum(lang_id));
2044 162 : if (!OidIsValid(oid) && !missing_ok)
2045 0 : ereport(ERROR,
2046 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2047 : errmsg("transform for type %s language \"%s\" does not exist",
2048 : format_type_be(type_id),
2049 : get_language_name(lang_id, false))));
2050 162 : return oid;
2051 : }
2052 :
2053 :
2054 : /*
2055 : * Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA/RENAME
2056 : *
2057 : * Is there a function with the given name and signature already in the given
2058 : * namespace? If so, raise an appropriate error message.
2059 : */
2060 : void
2061 136 : IsThereFunctionInNamespace(const char *proname, int pronargs,
2062 : oidvector *proargtypes, Oid nspOid)
2063 : {
2064 : /* check for duplicate name (more friendly than unique-index failure) */
2065 136 : if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2066 : CStringGetDatum(proname),
2067 : PointerGetDatum(proargtypes),
2068 : ObjectIdGetDatum(nspOid)))
2069 24 : ereport(ERROR,
2070 : (errcode(ERRCODE_DUPLICATE_FUNCTION),
2071 : errmsg("function %s already exists in schema \"%s\"",
2072 : funcname_signature_string(proname, pronargs,
2073 : NIL, proargtypes->values),
2074 : get_namespace_name(nspOid))));
2075 112 : }
2076 :
2077 : /*
2078 : * ExecuteDoStmt
2079 : * Execute inline procedural-language code
2080 : *
2081 : * See at ExecuteCallStmt() about the atomic argument.
2082 : */
2083 : void
2084 1574 : ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic)
2085 : {
2086 1574 : InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
2087 : ListCell *arg;
2088 1574 : DefElem *as_item = NULL;
2089 1574 : DefElem *language_item = NULL;
2090 : char *language;
2091 : Oid laninline;
2092 : HeapTuple languageTuple;
2093 : Form_pg_language languageStruct;
2094 :
2095 : /* Process options we got from gram.y */
2096 3346 : foreach(arg, stmt->args)
2097 : {
2098 1772 : DefElem *defel = (DefElem *) lfirst(arg);
2099 :
2100 1772 : if (strcmp(defel->defname, "as") == 0)
2101 : {
2102 1574 : if (as_item)
2103 0 : errorConflictingDefElem(defel, pstate);
2104 1574 : as_item = defel;
2105 : }
2106 198 : else if (strcmp(defel->defname, "language") == 0)
2107 : {
2108 198 : if (language_item)
2109 0 : errorConflictingDefElem(defel, pstate);
2110 198 : language_item = defel;
2111 : }
2112 : else
2113 0 : elog(ERROR, "option \"%s\" not recognized",
2114 : defel->defname);
2115 : }
2116 :
2117 1574 : if (as_item)
2118 1574 : codeblock->source_text = strVal(as_item->arg);
2119 : else
2120 0 : ereport(ERROR,
2121 : (errcode(ERRCODE_SYNTAX_ERROR),
2122 : errmsg("no inline code specified")));
2123 :
2124 : /* if LANGUAGE option wasn't specified, use the default */
2125 1574 : if (language_item)
2126 198 : language = strVal(language_item->arg);
2127 : else
2128 1376 : language = "plpgsql";
2129 :
2130 : /* Look up the language and validate permissions */
2131 1574 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2132 1574 : if (!HeapTupleIsValid(languageTuple))
2133 0 : ereport(ERROR,
2134 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2135 : errmsg("language \"%s\" does not exist", language),
2136 : (extension_file_exists(language) ?
2137 : errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
2138 :
2139 1574 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2140 1574 : codeblock->langOid = languageStruct->oid;
2141 1574 : codeblock->langIsTrusted = languageStruct->lanpltrusted;
2142 1574 : codeblock->atomic = atomic;
2143 :
2144 1574 : if (languageStruct->lanpltrusted)
2145 : {
2146 : /* if trusted language, need USAGE privilege */
2147 : AclResult aclresult;
2148 :
2149 1530 : aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(),
2150 : ACL_USAGE);
2151 1530 : if (aclresult != ACLCHECK_OK)
2152 0 : aclcheck_error(aclresult, OBJECT_LANGUAGE,
2153 0 : NameStr(languageStruct->lanname));
2154 : }
2155 : else
2156 : {
2157 : /* if untrusted language, must be superuser */
2158 44 : if (!superuser())
2159 0 : aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
2160 0 : NameStr(languageStruct->lanname));
2161 : }
2162 :
2163 : /* get the handler function's OID */
2164 1574 : laninline = languageStruct->laninline;
2165 1574 : if (!OidIsValid(laninline))
2166 0 : ereport(ERROR,
2167 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2168 : errmsg("language \"%s\" does not support inline code execution",
2169 : NameStr(languageStruct->lanname))));
2170 :
2171 1574 : ReleaseSysCache(languageTuple);
2172 :
2173 : /* execute the inline handler */
2174 1574 : OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2175 1172 : }
2176 :
2177 : /*
2178 : * Execute CALL statement
2179 : *
2180 : * Inside a top-level CALL statement, transaction-terminating commands such as
2181 : * COMMIT or a PL-specific equivalent are allowed. The terminology in the SQL
2182 : * standard is that CALL establishes a non-atomic execution context. Most
2183 : * other commands establish an atomic execution context, in which transaction
2184 : * control actions are not allowed. If there are nested executions of CALL,
2185 : * we want to track the execution context recursively, so that the nested
2186 : * CALLs can also do transaction control. Note, however, that for example in
2187 : * CALL -> SELECT -> CALL, the second call cannot do transaction control,
2188 : * because the SELECT in between establishes an atomic execution context.
2189 : *
2190 : * So when ExecuteCallStmt() is called from the top level, we pass in atomic =
2191 : * false (recall that that means transactions = yes). We then create a
2192 : * CallContext node with content atomic = false, which is passed in the
2193 : * fcinfo->context field to the procedure invocation. The language
2194 : * implementation should then take appropriate measures to allow or prevent
2195 : * transaction commands based on that information, e.g., call
2196 : * SPI_connect_ext(SPI_OPT_NONATOMIC). The language should also pass on the
2197 : * atomic flag to any nested invocations to CALL.
2198 : *
2199 : * The expression data structures and execution context that we create
2200 : * within this function are children of the portalContext of the Portal
2201 : * that the CALL utility statement runs in. Therefore, any pass-by-ref
2202 : * values that we're passing to the procedure will survive transaction
2203 : * commits that might occur inside the procedure.
2204 : */
2205 : void
2206 484 : ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
2207 : {
2208 484 : LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
2209 : ListCell *lc;
2210 : FuncExpr *fexpr;
2211 : int nargs;
2212 : int i;
2213 : AclResult aclresult;
2214 : FmgrInfo flinfo;
2215 : CallContext *callcontext;
2216 : EState *estate;
2217 : ExprContext *econtext;
2218 : HeapTuple tp;
2219 : PgStat_FunctionCallUsage fcusage;
2220 : Datum retval;
2221 :
2222 484 : fexpr = stmt->funcexpr;
2223 : Assert(fexpr);
2224 : Assert(IsA(fexpr, FuncExpr));
2225 :
2226 484 : aclresult = object_aclcheck(ProcedureRelationId, fexpr->funcid, GetUserId(), ACL_EXECUTE);
2227 484 : if (aclresult != ACLCHECK_OK)
2228 12 : aclcheck_error(aclresult, OBJECT_PROCEDURE, get_func_name(fexpr->funcid));
2229 :
2230 : /* Prep the context object we'll pass to the procedure */
2231 472 : callcontext = makeNode(CallContext);
2232 472 : callcontext->atomic = atomic;
2233 :
2234 472 : tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2235 472 : if (!HeapTupleIsValid(tp))
2236 0 : elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
2237 :
2238 : /*
2239 : * If proconfig is set we can't allow transaction commands because of the
2240 : * way the GUC stacking works: The transaction boundary would have to pop
2241 : * the proconfig setting off the stack. That restriction could be lifted
2242 : * by redesigning the GUC nesting mechanism a bit.
2243 : */
2244 472 : if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL))
2245 2 : callcontext->atomic = true;
2246 :
2247 : /*
2248 : * In security definer procedures, we can't allow transaction commands.
2249 : * StartTransaction() insists that the security context stack is empty,
2250 : * and AbortTransaction() resets the security context. This could be
2251 : * reorganized, but right now it doesn't work.
2252 : */
2253 472 : if (((Form_pg_proc) GETSTRUCT(tp))->prosecdef)
2254 2 : callcontext->atomic = true;
2255 :
2256 472 : ReleaseSysCache(tp);
2257 :
2258 : /* safety check; see ExecInitFunc() */
2259 472 : nargs = list_length(fexpr->args);
2260 472 : if (nargs > FUNC_MAX_ARGS)
2261 0 : ereport(ERROR,
2262 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2263 : errmsg_plural("cannot pass more than %d argument to a procedure",
2264 : "cannot pass more than %d arguments to a procedure",
2265 : FUNC_MAX_ARGS,
2266 : FUNC_MAX_ARGS)));
2267 :
2268 : /* Initialize function call structure */
2269 472 : InvokeFunctionExecuteHook(fexpr->funcid);
2270 472 : fmgr_info(fexpr->funcid, &flinfo);
2271 472 : fmgr_info_set_expr((Node *) fexpr, &flinfo);
2272 472 : InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
2273 : (Node *) callcontext, NULL);
2274 :
2275 : /*
2276 : * Evaluate procedure arguments inside a suitable execution context. Note
2277 : * we can't free this context till the procedure returns.
2278 : */
2279 472 : estate = CreateExecutorState();
2280 472 : estate->es_param_list_info = params;
2281 472 : econtext = CreateExprContext(estate);
2282 :
2283 : /*
2284 : * If we're called in non-atomic context, we also have to ensure that the
2285 : * argument expressions run with an up-to-date snapshot. Our caller will
2286 : * have provided a current snapshot in atomic contexts, but not in
2287 : * non-atomic contexts, because the possibility of a COMMIT/ROLLBACK
2288 : * destroying the snapshot makes higher-level management too complicated.
2289 : */
2290 472 : if (!atomic)
2291 434 : PushActiveSnapshot(GetTransactionSnapshot());
2292 :
2293 472 : i = 0;
2294 1100 : foreach(lc, fexpr->args)
2295 : {
2296 : ExprState *exprstate;
2297 : Datum val;
2298 : bool isnull;
2299 :
2300 628 : exprstate = ExecPrepareExpr(lfirst(lc), estate);
2301 :
2302 628 : val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
2303 :
2304 628 : fcinfo->args[i].value = val;
2305 628 : fcinfo->args[i].isnull = isnull;
2306 :
2307 628 : i++;
2308 : }
2309 :
2310 : /* Get rid of temporary snapshot for arguments, if we made one */
2311 472 : if (!atomic)
2312 434 : PopActiveSnapshot();
2313 :
2314 : /* Here we actually call the procedure */
2315 472 : pgstat_init_function_usage(fcinfo, &fcusage);
2316 472 : retval = FunctionCallInvoke(fcinfo);
2317 440 : pgstat_end_function_usage(&fcusage, true);
2318 :
2319 : /* Handle the procedure's outputs */
2320 440 : if (fexpr->funcresulttype == VOIDOID)
2321 : {
2322 : /* do nothing */
2323 : }
2324 202 : else if (fexpr->funcresulttype == RECORDOID)
2325 : {
2326 : /* send tuple to client */
2327 : HeapTupleHeader td;
2328 : Oid tupType;
2329 : int32 tupTypmod;
2330 : TupleDesc retdesc;
2331 : HeapTupleData rettupdata;
2332 : TupOutputState *tstate;
2333 : TupleTableSlot *slot;
2334 :
2335 202 : if (fcinfo->isnull)
2336 0 : elog(ERROR, "procedure returned null record");
2337 :
2338 : /*
2339 : * Ensure there's an active snapshot whilst we execute whatever's
2340 : * involved here. Note that this is *not* sufficient to make the
2341 : * world safe for TOAST pointers to be included in the returned data:
2342 : * the referenced data could have gone away while we didn't hold a
2343 : * snapshot. Hence, it's incumbent on PLs that can do COMMIT/ROLLBACK
2344 : * to not return TOAST pointers, unless those pointers were fetched
2345 : * after the last COMMIT/ROLLBACK in the procedure.
2346 : *
2347 : * XXX that is a really nasty, hard-to-test requirement. Is there a
2348 : * way to remove it?
2349 : */
2350 202 : EnsurePortalSnapshotExists();
2351 :
2352 202 : td = DatumGetHeapTupleHeader(retval);
2353 202 : tupType = HeapTupleHeaderGetTypeId(td);
2354 202 : tupTypmod = HeapTupleHeaderGetTypMod(td);
2355 202 : retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
2356 :
2357 202 : tstate = begin_tup_output_tupdesc(dest, retdesc,
2358 : &TTSOpsHeapTuple);
2359 :
2360 202 : rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
2361 202 : ItemPointerSetInvalid(&(rettupdata.t_self));
2362 202 : rettupdata.t_tableOid = InvalidOid;
2363 202 : rettupdata.t_data = td;
2364 :
2365 202 : slot = ExecStoreHeapTuple(&rettupdata, tstate->slot, false);
2366 202 : tstate->dest->receiveSlot(slot, tstate->dest);
2367 :
2368 202 : end_tup_output(tstate);
2369 :
2370 202 : ReleaseTupleDesc(retdesc);
2371 : }
2372 : else
2373 0 : elog(ERROR, "unexpected result type for procedure: %u",
2374 : fexpr->funcresulttype);
2375 :
2376 440 : FreeExecutorState(estate);
2377 440 : }
2378 :
2379 : /*
2380 : * Construct the tuple descriptor for a CALL statement return
2381 : */
2382 : TupleDesc
2383 196 : CallStmtResultDesc(CallStmt *stmt)
2384 : {
2385 : FuncExpr *fexpr;
2386 : HeapTuple tuple;
2387 : TupleDesc tupdesc;
2388 :
2389 196 : fexpr = stmt->funcexpr;
2390 :
2391 196 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2392 196 : if (!HeapTupleIsValid(tuple))
2393 0 : elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
2394 :
2395 196 : tupdesc = build_function_result_tupdesc_t(tuple);
2396 :
2397 196 : ReleaseSysCache(tuple);
2398 :
2399 : /*
2400 : * The result of build_function_result_tupdesc_t has the right column
2401 : * names, but it just has the declared output argument types, which is the
2402 : * wrong thing in polymorphic cases. Get the correct types by examining
2403 : * stmt->outargs. We intentionally keep the atttypmod as -1 and the
2404 : * attcollation as the type's default, since that's always the appropriate
2405 : * thing for function outputs; there's no point in considering any
2406 : * additional info available from outargs. Note that tupdesc is null if
2407 : * there are no outargs.
2408 : */
2409 196 : if (tupdesc)
2410 : {
2411 : Assert(tupdesc->natts == list_length(stmt->outargs));
2412 502 : for (int i = 0; i < tupdesc->natts; i++)
2413 : {
2414 306 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2415 306 : Node *outarg = (Node *) list_nth(stmt->outargs, i);
2416 :
2417 306 : TupleDescInitEntry(tupdesc,
2418 306 : i + 1,
2419 306 : NameStr(att->attname),
2420 : exprType(outarg),
2421 : -1,
2422 : 0);
2423 : }
2424 : }
2425 :
2426 196 : return tupdesc;
2427 : }
|