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