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