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