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