Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * functioncmds.c
4 : *
5 : * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
6 : * CAST commands.
7 : *
8 : * Portions Copyright (c) 1996-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
83 738 : 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 738 : typtup = LookupTypeName(NULL, returnType, NULL, false);
91 :
92 738 : if (typtup)
93 : {
94 736 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
95 : {
96 5 : if (languageOid == SQLlanguageId)
97 0 : ereport(ERROR,
98 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
99 : errmsg("SQL function cannot return shell type %s",
100 : TypeNameToString(returnType))));
101 : else
102 5 : ereport(NOTICE,
103 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
104 : errmsg("return type %s is only a shell",
105 : TypeNameToString(returnType))));
106 : }
107 736 : rettype = typeTypeId(typtup);
108 736 : ReleaseSysCache(typtup);
109 : }
110 : else
111 : {
112 2 : 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 2 : if (languageOid != INTERNALlanguageId &&
125 : languageOid != ClanguageId)
126 0 : 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 2 : if (returnType->typmods != NIL)
132 0 : 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 2 : ereport(NOTICE,
139 : (errcode(ERRCODE_UNDEFINED_OBJECT),
140 : errmsg("type \"%s\" is not yet defined", typnam),
141 : errdetail("Creating a shell type definition.")));
142 2 : namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
143 : &typname);
144 2 : aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
145 : ACL_CREATE);
146 2 : if (aclresult != ACLCHECK_OK)
147 0 : aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
148 0 : get_namespace_name(namespaceId));
149 2 : address = TypeShellMake(typname, namespaceId, GetUserId());
150 2 : rettype = address.objectId;
151 2 : Assert(OidIsValid(rettype));
152 : }
153 :
154 738 : aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
155 738 : if (aclresult != ACLCHECK_OK)
156 1 : aclcheck_error_type(aclresult, rettype);
157 :
158 737 : *prorettype_p = rettype;
159 737 : *returnsSet_p = returnType->setof;
160 737 : }
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
179 826 : 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 826 : int parameterCount = list_length(parameters);
192 : Oid *inTypes;
193 826 : int inCount = 0;
194 : Datum *allTypes;
195 : Datum *paramModes;
196 : Datum *paramNames;
197 826 : int outCount = 0;
198 826 : int varCount = 0;
199 826 : bool have_names = false;
200 826 : bool have_defaults = false;
201 : ListCell *x;
202 : int i;
203 :
204 826 : *variadicArgType = InvalidOid; /* default result */
205 826 : *requiredResultType = InvalidOid; /* default result */
206 :
207 826 : inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
208 826 : allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
209 826 : paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
210 826 : paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
211 826 : *parameterDefaults = NIL;
212 :
213 : /* Scan the list and extract data into work arrays */
214 826 : i = 0;
215 2200 : foreach(x, parameters)
216 : {
217 1382 : FunctionParameter *fp = (FunctionParameter *) lfirst(x);
218 1382 : TypeName *t = fp->argType;
219 1382 : bool isinput = false;
220 : Oid toid;
221 : Type typtup;
222 : AclResult aclresult;
223 :
224 1382 : typtup = LookupTypeName(NULL, t, NULL, false);
225 1382 : if (typtup)
226 : {
227 1382 : if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
228 : {
229 : /* As above, hard error if language is SQL */
230 7 : if (languageOid == SQLlanguageId)
231 0 : 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 7 : else if (is_aggregate)
237 0 : ereport(ERROR,
238 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
239 : errmsg("aggregate cannot accept shell type %s",
240 : TypeNameToString(t))));
241 : else
242 7 : ereport(NOTICE,
243 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
244 : errmsg("argument type %s is only a shell",
245 : TypeNameToString(t))));
246 : }
247 1382 : toid = typeTypeId(typtup);
248 1382 : ReleaseSysCache(typtup);
249 : }
250 : else
251 : {
252 0 : 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 1382 : aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
260 1382 : if (aclresult != ACLCHECK_OK)
261 2 : aclcheck_error_type(aclresult, toid);
262 :
263 1380 : if (t->setof)
264 : {
265 0 : if (is_aggregate)
266 0 : ereport(ERROR,
267 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
268 : errmsg("aggregates cannot accept set arguments")));
269 : else
270 0 : ereport(ERROR,
271 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
272 : errmsg("functions cannot accept set arguments")));
273 : }
274 :
275 : /* handle input parameters */
276 1380 : if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
277 : {
278 : /* other input parameters can't follow a VARIADIC parameter */
279 1252 : if (varCount > 0)
280 0 : ereport(ERROR,
281 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
282 : errmsg("VARIADIC parameter must be the last input parameter")));
283 1252 : inTypes[inCount++] = toid;
284 1252 : isinput = true;
285 : }
286 :
287 : /* handle output parameters */
288 1380 : if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
289 : {
290 136 : if (outCount == 0) /* save first output param's type */
291 68 : *requiredResultType = toid;
292 136 : outCount++;
293 : }
294 :
295 1380 : if (fp->mode == FUNC_PARAM_VARIADIC)
296 : {
297 15 : *variadicArgType = toid;
298 15 : varCount++;
299 : /* validate variadic parameter type */
300 15 : switch (toid)
301 : {
302 : case ANYARRAYOID:
303 : case ANYOID:
304 : /* okay */
305 6 : break;
306 : default:
307 9 : if (!OidIsValid(get_element_type(toid)))
308 0 : ereport(ERROR,
309 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
310 : errmsg("VARIADIC parameter must be an array")));
311 9 : break;
312 : }
313 : }
314 :
315 1380 : allTypes[i] = ObjectIdGetDatum(toid);
316 :
317 1380 : paramModes[i] = CharGetDatum(fp->mode);
318 :
319 1380 : 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 720 : foreach(px, parameters)
330 : {
331 720 : FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
332 :
333 720 : if (prevfp == fp)
334 320 : break;
335 : /* pure in doesn't conflict with pure out */
336 687 : if ((fp->mode == FUNC_PARAM_IN ||
337 412 : fp->mode == FUNC_PARAM_VARIADIC) &&
338 246 : (prevfp->mode == FUNC_PARAM_OUT ||
339 121 : prevfp->mode == FUNC_PARAM_TABLE))
340 4 : continue;
341 506 : if ((prevfp->mode == FUNC_PARAM_IN ||
342 408 : prevfp->mode == FUNC_PARAM_VARIADIC) &&
343 463 : (fp->mode == FUNC_PARAM_OUT ||
344 165 : fp->mode == FUNC_PARAM_TABLE))
345 175 : continue;
346 442 : if (prevfp->name && prevfp->name[0] &&
347 221 : strcmp(prevfp->name, fp->name) == 0)
348 4 : ereport(ERROR,
349 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
350 : errmsg("parameter name \"%s\" used more than once",
351 : fp->name)));
352 : }
353 :
354 320 : paramNames[i] = CStringGetTextDatum(fp->name);
355 320 : have_names = true;
356 : }
357 :
358 1376 : if (fp->defexpr)
359 : {
360 : Node *def;
361 :
362 61 : if (!isinput)
363 1 : ereport(ERROR,
364 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
365 : errmsg("only input parameters can have default values")));
366 :
367 60 : def = transformExpr(pstate, fp->defexpr,
368 : EXPR_KIND_FUNCTION_DEFAULT);
369 60 : def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
370 60 : 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 120 : if (list_length(pstate->p_rtable) != 0 ||
377 60 : contain_var_clause(def))
378 0 : 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 60 : *parameterDefaults = lappend(*parameterDefaults, def);
397 60 : have_defaults = true;
398 : }
399 : else
400 : {
401 1315 : if (isinput && have_defaults)
402 1 : 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 1374 : i++;
408 : }
409 :
410 : /* Now construct the proper outputs as needed */
411 818 : *parameterTypes = buildoidvector(inTypes, inCount);
412 :
413 818 : if (outCount > 0 || varCount > 0)
414 : {
415 75 : *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
416 : sizeof(Oid), true, 'i');
417 75 : *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
418 : 1, true, 'c');
419 150 : if (outCount > 1)
420 45 : *requiredResultType = RECORDOID;
421 : /* otherwise we set requiredResultType correctly above */
422 : }
423 : else
424 : {
425 743 : *allParameterTypes = NULL;
426 743 : *parameterModes = NULL;
427 : }
428 :
429 818 : if (have_names)
430 : {
431 457 : for (i = 0; i < parameterCount; i++)
432 : {
433 322 : if (paramNames[i] == PointerGetDatum(NULL))
434 8 : paramNames[i] = CStringGetTextDatum("");
435 : }
436 135 : *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
437 : -1, false, 'i');
438 : }
439 : else
440 683 : *parameterNames = NULL;
441 818 : }
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
453 539 : 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 539 : if (strcmp(defel->defname, "volatility") == 0)
465 : {
466 129 : if (*volatility_item)
467 0 : goto duplicate_error;
468 :
469 129 : *volatility_item = defel;
470 : }
471 410 : else if (strcmp(defel->defname, "strict") == 0)
472 : {
473 218 : if (*strict_item)
474 0 : goto duplicate_error;
475 :
476 218 : *strict_item = defel;
477 : }
478 192 : else if (strcmp(defel->defname, "security") == 0)
479 : {
480 7 : if (*security_item)
481 0 : goto duplicate_error;
482 :
483 7 : *security_item = defel;
484 : }
485 185 : else if (strcmp(defel->defname, "leakproof") == 0)
486 : {
487 7 : if (*leakproof_item)
488 0 : goto duplicate_error;
489 :
490 7 : *leakproof_item = defel;
491 : }
492 178 : else if (strcmp(defel->defname, "set") == 0)
493 : {
494 9 : *set_items = lappend(*set_items, defel->arg);
495 : }
496 169 : else if (strcmp(defel->defname, "cost") == 0)
497 : {
498 9 : if (*cost_item)
499 0 : goto duplicate_error;
500 :
501 9 : *cost_item = defel;
502 : }
503 160 : else if (strcmp(defel->defname, "rows") == 0)
504 : {
505 5 : if (*rows_item)
506 0 : goto duplicate_error;
507 :
508 5 : *rows_item = defel;
509 : }
510 155 : else if (strcmp(defel->defname, "parallel") == 0)
511 : {
512 155 : if (*parallel_item)
513 0 : goto duplicate_error;
514 :
515 155 : *parallel_item = defel;
516 : }
517 : else
518 0 : return false;
519 :
520 : /* Recognized an option */
521 539 : return true;
522 :
523 : duplicate_error:
524 0 : 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
532 129 : interpret_func_volatility(DefElem *defel)
533 : {
534 129 : char *str = strVal(defel->arg);
535 :
536 129 : if (strcmp(str, "immutable") == 0)
537 88 : return PROVOLATILE_IMMUTABLE;
538 41 : else if (strcmp(str, "stable") == 0)
539 22 : return PROVOLATILE_STABLE;
540 19 : else if (strcmp(str, "volatile") == 0)
541 19 : return PROVOLATILE_VOLATILE;
542 : else
543 : {
544 0 : elog(ERROR, "invalid volatility \"%s\"", str);
545 : return 0; /* keep compiler quiet */
546 : }
547 : }
548 :
549 : static char
550 155 : interpret_func_parallel(DefElem *defel)
551 : {
552 155 : char *str = strVal(defel->arg);
553 :
554 155 : if (strcmp(str, "safe") == 0)
555 152 : return PROPARALLEL_SAFE;
556 3 : else if (strcmp(str, "unsafe") == 0)
557 0 : return PROPARALLEL_UNSAFE;
558 3 : else if (strcmp(str, "restricted") == 0)
559 3 : return PROPARALLEL_RESTRICTED;
560 : else
561 : {
562 0 : 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 *
575 9 : update_proconfig_value(ArrayType *a, List *set_items)
576 : {
577 : ListCell *l;
578 :
579 18 : foreach(l, set_items)
580 : {
581 9 : VariableSetStmt *sstmt = lfirst_node(VariableSetStmt, l);
582 :
583 9 : if (sstmt->kind == VAR_RESET_ALL)
584 2 : a = NULL;
585 : else
586 : {
587 7 : char *valuestr = ExtractSetVariableArgs(sstmt);
588 :
589 7 : if (valuestr)
590 7 : a = GUCArrayAdd(a, sstmt->name, valuestr);
591 : else /* RESET */
592 0 : a = GUCArrayDelete(a, sstmt->name);
593 : }
594 : }
595 :
596 9 : return a;
597 : }
598 :
599 :
600 : /*
601 : * Dissect the list of options assembled in gram.y into function
602 : * attributes.
603 : */
604 : static void
605 767 : 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 767 : DefElem *as_item = NULL;
622 767 : DefElem *language_item = NULL;
623 767 : DefElem *transform_item = NULL;
624 767 : DefElem *windowfunc_item = NULL;
625 767 : DefElem *volatility_item = NULL;
626 767 : DefElem *strict_item = NULL;
627 767 : DefElem *security_item = NULL;
628 767 : DefElem *leakproof_item = NULL;
629 767 : List *set_items = NIL;
630 767 : DefElem *cost_item = NULL;
631 767 : DefElem *rows_item = NULL;
632 767 : DefElem *parallel_item = NULL;
633 :
634 2822 : foreach(option, options)
635 : {
636 2055 : DefElem *defel = (DefElem *) lfirst(option);
637 :
638 2055 : if (strcmp(defel->defname, "as") == 0)
639 : {
640 767 : if (as_item)
641 0 : ereport(ERROR,
642 : (errcode(ERRCODE_SYNTAX_ERROR),
643 : errmsg("conflicting or redundant options"),
644 : parser_errposition(pstate, defel->location)));
645 767 : as_item = defel;
646 : }
647 1288 : else if (strcmp(defel->defname, "language") == 0)
648 : {
649 767 : if (language_item)
650 0 : ereport(ERROR,
651 : (errcode(ERRCODE_SYNTAX_ERROR),
652 : errmsg("conflicting or redundant options"),
653 : parser_errposition(pstate, defel->location)));
654 767 : language_item = defel;
655 : }
656 521 : else if (strcmp(defel->defname, "transform") == 0)
657 : {
658 0 : if (transform_item)
659 0 : ereport(ERROR,
660 : (errcode(ERRCODE_SYNTAX_ERROR),
661 : errmsg("conflicting or redundant options"),
662 : parser_errposition(pstate, defel->location)));
663 0 : transform_item = defel;
664 : }
665 521 : else if (strcmp(defel->defname, "window") == 0)
666 : {
667 1 : if (windowfunc_item)
668 0 : ereport(ERROR,
669 : (errcode(ERRCODE_SYNTAX_ERROR),
670 : errmsg("conflicting or redundant options"),
671 : parser_errposition(pstate, defel->location)));
672 1 : windowfunc_item = defel;
673 : }
674 520 : 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 520 : continue;
687 : }
688 : else
689 0 : elog(ERROR, "option \"%s\" not recognized",
690 : defel->defname);
691 : }
692 :
693 : /* process required items */
694 767 : if (as_item)
695 767 : *as = (List *) as_item->arg;
696 : else
697 : {
698 0 : ereport(ERROR,
699 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
700 : errmsg("no function body specified")));
701 : *as = NIL; /* keep compiler quiet */
702 : }
703 :
704 767 : if (language_item)
705 767 : *language = strVal(language_item->arg);
706 : else
707 : {
708 0 : 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 767 : if (transform_item)
716 0 : *transform = transform_item->arg;
717 767 : if (windowfunc_item)
718 1 : *windowfunc_p = intVal(windowfunc_item->arg);
719 767 : if (volatility_item)
720 124 : *volatility_p = interpret_func_volatility(volatility_item);
721 767 : if (strict_item)
722 214 : *strict_p = intVal(strict_item->arg);
723 767 : if (security_item)
724 5 : *security_definer = intVal(security_item->arg);
725 767 : if (leakproof_item)
726 3 : *leakproof_p = intVal(leakproof_item->arg);
727 767 : if (set_items)
728 6 : *proconfig = update_proconfig_value(NULL, set_items);
729 767 : if (cost_item)
730 : {
731 8 : *procost = defGetNumeric(cost_item);
732 8 : if (*procost <= 0)
733 0 : ereport(ERROR,
734 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
735 : errmsg("COST must be positive")));
736 : }
737 767 : if (rows_item)
738 : {
739 5 : *prorows = defGetNumeric(rows_item);
740 5 : if (*prorows <= 0)
741 0 : ereport(ERROR,
742 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
743 : errmsg("ROWS must be positive")));
744 : }
745 767 : if (parallel_item)
746 155 : *parallel_p = interpret_func_parallel(parallel_item);
747 767 : }
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
765 755 : compute_attributes_with_style(ParseState *pstate, List *parameters, bool *isStrict_p, char *volatility_p)
766 : {
767 : ListCell *pl;
768 :
769 755 : foreach(pl, parameters)
770 : {
771 0 : DefElem *param = (DefElem *) lfirst(pl);
772 :
773 0 : if (pg_strcasecmp(param->defname, "isstrict") == 0)
774 0 : *isStrict_p = defGetBoolean(param);
775 0 : else if (pg_strcasecmp(param->defname, "iscachable") == 0)
776 : {
777 : /* obsolete spelling of isImmutable */
778 0 : if (defGetBoolean(param))
779 0 : *volatility_p = PROVOLATILE_IMMUTABLE;
780 : }
781 : else
782 0 : 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 755 : }
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
801 755 : interpret_AS_clause(Oid languageOid, const char *languageName,
802 : char *funcname, List *as,
803 : char **prosrc_str_p, char **probin_str_p)
804 : {
805 755 : Assert(as != NIL);
806 :
807 755 : 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 153 : *probin_str_p = strVal(linitial(as));
818 153 : if (list_length(as) == 1)
819 18 : *prosrc_str_p = funcname;
820 : else
821 : {
822 135 : *prosrc_str_p = strVal(lsecond(as));
823 135 : if (strcmp(*prosrc_str_p, "-") == 0)
824 0 : *prosrc_str_p = funcname;
825 : }
826 : }
827 : else
828 : {
829 : /* Everything else wants the given string in prosrc. */
830 602 : *prosrc_str_p = strVal(linitial(as));
831 602 : *probin_str_p = NULL;
832 :
833 602 : if (list_length(as) != 1)
834 1 : ereport(ERROR,
835 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
836 : errmsg("only one AS item needed for language \"%s\"",
837 : languageName)));
838 :
839 601 : 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 35 : if (strlen(*prosrc_str_p) == 0)
850 0 : *prosrc_str_p = funcname;
851 : }
852 : }
853 754 : }
854 :
855 :
856 : /*
857 : * CreateFunction
858 : * Execute a CREATE FUNCTION utility statement.
859 : */
860 : ObjectAddress
861 767 : 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 767 : 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 767 : 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 767 : namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
898 : &funcname);
899 :
900 : /* Check we have creation rights in target namespace */
901 767 : aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
902 767 : if (aclresult != ACLCHECK_OK)
903 0 : aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
904 0 : get_namespace_name(namespaceId));
905 :
906 : /* default attributes */
907 767 : isWindowFunc = false;
908 767 : isStrict = false;
909 767 : security = false;
910 767 : isLeakProof = false;
911 767 : volatility = PROVOLATILE_VOLATILE;
912 767 : proconfig = NULL;
913 767 : procost = -1; /* indicates not set */
914 767 : prorows = -1; /* indicates not set */
915 767 : parallel = PROPARALLEL_UNSAFE;
916 :
917 : /* override attributes from explicit list */
918 767 : 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 767 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
927 767 : if (!HeapTupleIsValid(languageTuple))
928 0 : 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 767 : languageOid = HeapTupleGetOid(languageTuple);
935 767 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
936 :
937 767 : if (languageStruct->lanpltrusted)
938 : {
939 : /* if trusted language, need USAGE privilege */
940 : AclResult aclresult;
941 :
942 579 : aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
943 579 : if (aclresult != ACLCHECK_OK)
944 1 : aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
945 1 : NameStr(languageStruct->lanname));
946 : }
947 : else
948 : {
949 : /* if untrusted language, must be superuser */
950 188 : if (!superuser())
951 0 : aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
952 0 : NameStr(languageStruct->lanname));
953 : }
954 :
955 766 : languageValidator = languageStruct->lanvalidator;
956 :
957 766 : 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 766 : if (isLeakProof && !superuser())
965 1 : ereport(ERROR,
966 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
967 : errmsg("only superuser can define a leakproof function")));
968 :
969 765 : if (transformDefElem)
970 : {
971 : ListCell *lc;
972 :
973 0 : foreach(lc, castNode(List, transformDefElem))
974 : {
975 0 : Oid typeid = typenameTypeId(NULL,
976 0 : lfirst_node(TypeName, lc));
977 0 : Oid elt = get_base_element_type(typeid);
978 :
979 0 : typeid = elt ? elt : typeid;
980 :
981 0 : get_transform_oid(typeid, languageOid, false);
982 0 : 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 765 : 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 758 : if (stmt->returnType)
1003 : {
1004 : /* explicit RETURNS clause */
1005 738 : compute_return_type(stmt->returnType, languageOid,
1006 : &prorettype, &returnsSet);
1007 737 : if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1008 2 : 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 20 : else if (OidIsValid(requiredResultType))
1014 : {
1015 : /* default RETURNS clause from OUT parameters */
1016 20 : prorettype = requiredResultType;
1017 20 : returnsSet = false;
1018 : }
1019 : else
1020 : {
1021 0 : 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 755 : if (list_length(trftypes_list) > 0)
1030 : {
1031 : ListCell *lc;
1032 : Datum *arr;
1033 : int i;
1034 :
1035 0 : arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1036 0 : i = 0;
1037 0 : foreach(lc, trftypes_list)
1038 0 : arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1039 0 : 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 755 : trftypes = NULL;
1046 : }
1047 :
1048 755 : compute_attributes_with_style(pstate, stmt->withClause, &isStrict, &volatility);
1049 :
1050 755 : 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 754 : if (procost < 0)
1059 : {
1060 : /* SQL and PL-language functions are assumed more expensive */
1061 746 : if (languageOid == INTERNALlanguageId ||
1062 : languageOid == ClanguageId)
1063 184 : procost = 1;
1064 : else
1065 562 : procost = 100;
1066 : }
1067 754 : if (prorows < 0)
1068 : {
1069 749 : if (returnsSet)
1070 74 : prorows = 1000;
1071 : else
1072 675 : prorows = 0; /* dummy value if not returnsSet */
1073 : }
1074 5 : else if (!returnsSet)
1075 0 : 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 1508 : return ProcedureCreate(funcname,
1084 : namespaceId,
1085 754 : 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
1118 266 : RemoveFunctionById(Oid funcOid)
1119 : {
1120 : Relation relation;
1121 : HeapTuple tup;
1122 : bool isagg;
1123 :
1124 : /*
1125 : * Delete the pg_proc tuple.
1126 : */
1127 266 : relation = heap_open(ProcedureRelationId, RowExclusiveLock);
1128 :
1129 266 : tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1130 266 : if (!HeapTupleIsValid(tup)) /* should not happen */
1131 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1132 :
1133 266 : isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
1134 :
1135 266 : CatalogTupleDelete(relation, &tup->t_self);
1136 :
1137 266 : ReleaseSysCache(tup);
1138 :
1139 266 : heap_close(relation, RowExclusiveLock);
1140 :
1141 : /*
1142 : * If there's a pg_aggregate tuple, delete that too.
1143 : */
1144 266 : if (isagg)
1145 : {
1146 19 : relation = heap_open(AggregateRelationId, RowExclusiveLock);
1147 :
1148 19 : tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1149 19 : if (!HeapTupleIsValid(tup)) /* should not happen */
1150 0 : elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1151 :
1152 19 : CatalogTupleDelete(relation, &tup->t_self);
1153 :
1154 19 : ReleaseSysCache(tup);
1155 :
1156 19 : heap_close(relation, RowExclusiveLock);
1157 : }
1158 266 : }
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
1166 19 : AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
1167 : {
1168 : HeapTuple tup;
1169 : Oid funcOid;
1170 : Form_pg_proc procForm;
1171 : Relation rel;
1172 : ListCell *l;
1173 19 : DefElem *volatility_item = NULL;
1174 19 : DefElem *strict_item = NULL;
1175 19 : DefElem *security_def_item = NULL;
1176 19 : DefElem *leakproof_item = NULL;
1177 19 : List *set_items = NIL;
1178 19 : DefElem *cost_item = NULL;
1179 19 : DefElem *rows_item = NULL;
1180 19 : DefElem *parallel_item = NULL;
1181 : ObjectAddress address;
1182 :
1183 19 : rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1184 :
1185 19 : funcOid = LookupFuncWithArgs(stmt->func, false);
1186 :
1187 19 : tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1188 19 : if (!HeapTupleIsValid(tup)) /* should not happen */
1189 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1190 :
1191 19 : procForm = (Form_pg_proc) GETSTRUCT(tup);
1192 :
1193 : /* Permission check: must own function */
1194 19 : if (!pg_proc_ownercheck(funcOid, GetUserId()))
1195 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
1196 0 : NameListToString(stmt->func->objname));
1197 :
1198 19 : if (procForm->proisagg)
1199 0 : 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 38 : foreach(l, stmt->actions)
1206 : {
1207 19 : DefElem *defel = (DefElem *) lfirst(l);
1208 :
1209 19 : 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 0 : elog(ERROR, "option \"%s\" not recognized", defel->defname);
1220 : }
1221 :
1222 19 : if (volatility_item)
1223 5 : procForm->provolatile = interpret_func_volatility(volatility_item);
1224 19 : if (strict_item)
1225 4 : procForm->proisstrict = intVal(strict_item->arg);
1226 19 : if (security_def_item)
1227 2 : procForm->prosecdef = intVal(security_def_item->arg);
1228 19 : if (leakproof_item)
1229 : {
1230 4 : procForm->proleakproof = intVal(leakproof_item->arg);
1231 4 : if (procForm->proleakproof && !superuser())
1232 1 : ereport(ERROR,
1233 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1234 : errmsg("only superuser can define a leakproof function")));
1235 : }
1236 18 : if (cost_item)
1237 : {
1238 1 : procForm->procost = defGetNumeric(cost_item);
1239 1 : if (procForm->procost <= 0)
1240 0 : ereport(ERROR,
1241 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1242 : errmsg("COST must be positive")));
1243 : }
1244 18 : if (rows_item)
1245 : {
1246 0 : procForm->prorows = defGetNumeric(rows_item);
1247 0 : if (procForm->prorows <= 0)
1248 0 : ereport(ERROR,
1249 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1250 : errmsg("ROWS must be positive")));
1251 0 : if (!procForm->proretset)
1252 0 : ereport(ERROR,
1253 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1254 : errmsg("ROWS is not applicable when function does not return a set")));
1255 : }
1256 18 : 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 3 : datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1267 3 : a = isnull ? NULL : DatumGetArrayTypeP(datum);
1268 :
1269 : /* update according to each SET or RESET item, left to right */
1270 3 : a = update_proconfig_value(a, set_items);
1271 :
1272 : /* update the tuple */
1273 3 : memset(repl_repl, false, sizeof(repl_repl));
1274 3 : repl_repl[Anum_pg_proc_proconfig - 1] = true;
1275 :
1276 3 : if (a == NULL)
1277 : {
1278 2 : repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1279 2 : repl_null[Anum_pg_proc_proconfig - 1] = true;
1280 : }
1281 : else
1282 : {
1283 1 : repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1284 1 : repl_null[Anum_pg_proc_proconfig - 1] = false;
1285 : }
1286 :
1287 3 : tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1288 : repl_val, repl_null, repl_repl);
1289 : }
1290 18 : if (parallel_item)
1291 0 : procForm->proparallel = interpret_func_parallel(parallel_item);
1292 :
1293 : /* Do the update */
1294 18 : CatalogTupleUpdate(rel, &tup->t_self, tup);
1295 :
1296 18 : InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1297 :
1298 18 : ObjectAddressSet(address, ProcedureRelationId, funcOid);
1299 :
1300 18 : heap_close(rel, NoLock);
1301 18 : heap_freetuple(tup);
1302 :
1303 18 : 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
1314 2 : 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 2 : pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1323 :
1324 2 : tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1325 2 : if (!HeapTupleIsValid(tup)) /* should not happen */
1326 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1327 2 : procForm = (Form_pg_proc) GETSTRUCT(tup);
1328 :
1329 2 : if (procForm->prorettype != OPAQUEOID) /* caller messed up */
1330 0 : elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
1331 :
1332 : /* okay to overwrite copied tuple */
1333 2 : procForm->prorettype = newRetType;
1334 :
1335 : /* update the catalog and its indexes */
1336 2 : CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup);
1337 :
1338 2 : 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 2 : ObjectAddressSet(type_address, TypeRelationId, newRetType);
1345 2 : ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
1346 2 : recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
1347 2 : }
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
1356 1 : 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 1 : pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
1365 :
1366 1 : tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1367 1 : if (!HeapTupleIsValid(tup)) /* should not happen */
1368 0 : elog(ERROR, "cache lookup failed for function %u", funcOid);
1369 1 : procForm = (Form_pg_proc) GETSTRUCT(tup);
1370 :
1371 2 : if (argIndex < 0 || argIndex >= procForm->pronargs ||
1372 1 : procForm->proargtypes.values[argIndex] != OPAQUEOID)
1373 0 : elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
1374 :
1375 : /* okay to overwrite copied tuple */
1376 1 : procForm->proargtypes.values[argIndex] = newArgType;
1377 :
1378 : /* update the catalog and its indexes */
1379 1 : CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup);
1380 :
1381 1 : 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 1 : ObjectAddressSet(type_address, TypeRelationId, newArgType);
1388 1 : ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
1389 1 : recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
1390 1 : }
1391 :
1392 :
1393 :
1394 : /*
1395 : * CREATE CAST
1396 : */
1397 : ObjectAddress
1398 11 : 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 11 : sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
1418 11 : targettypeid = typenameTypeId(NULL, stmt->targettype);
1419 11 : sourcetyptype = get_typtype(sourcetypeid);
1420 11 : targettyptype = get_typtype(targettypeid);
1421 :
1422 : /* No pseudo-types allowed */
1423 11 : if (sourcetyptype == TYPTYPE_PSEUDO)
1424 0 : ereport(ERROR,
1425 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1426 : errmsg("source data type %s is a pseudo-type",
1427 : TypeNameToString(stmt->sourcetype))));
1428 :
1429 11 : if (targettyptype == TYPTYPE_PSEUDO)
1430 0 : 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 11 : if (!pg_type_ownercheck(sourcetypeid, GetUserId())
1437 2 : && !pg_type_ownercheck(targettypeid, GetUserId()))
1438 0 : 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 11 : aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
1445 11 : if (aclresult != ACLCHECK_OK)
1446 1 : aclcheck_error_type(aclresult, sourcetypeid);
1447 :
1448 10 : aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
1449 10 : if (aclresult != ACLCHECK_OK)
1450 0 : aclcheck_error_type(aclresult, targettypeid);
1451 :
1452 : /* Domains are allowed for historical reasons, but we warn */
1453 10 : if (sourcetyptype == TYPTYPE_DOMAIN)
1454 1 : ereport(WARNING,
1455 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1456 : errmsg("cast will be ignored because the source data type is a domain")));
1457 :
1458 9 : else if (targettyptype == TYPTYPE_DOMAIN)
1459 0 : 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 10 : if (stmt->func != NULL)
1465 3 : castmethod = COERCION_METHOD_FUNCTION;
1466 7 : else if (stmt->inout)
1467 1 : castmethod = COERCION_METHOD_INOUT;
1468 : else
1469 6 : castmethod = COERCION_METHOD_BINARY;
1470 :
1471 10 : if (castmethod == COERCION_METHOD_FUNCTION)
1472 : {
1473 : Form_pg_proc procstruct;
1474 :
1475 3 : funcid = LookupFuncWithArgs(stmt->func, false);
1476 :
1477 3 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1478 3 : if (!HeapTupleIsValid(tuple))
1479 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
1480 :
1481 3 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1482 3 : nargs = procstruct->pronargs;
1483 3 : if (nargs < 1 || nargs > 3)
1484 0 : ereport(ERROR,
1485 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1486 : errmsg("cast function must take one to three arguments")));
1487 3 : if (!IsBinaryCoercible(sourcetypeid, procstruct->proargtypes.values[0]))
1488 0 : 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 3 : if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1492 0 : ereport(ERROR,
1493 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1494 : errmsg("second argument of cast function must be type %s",
1495 : "integer")));
1496 3 : if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1497 0 : ereport(ERROR,
1498 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1499 : errmsg("third argument of cast function must be type %s",
1500 : "boolean")));
1501 3 : if (!IsBinaryCoercible(procstruct->prorettype, targettypeid))
1502 0 : 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 3 : if (procstruct->proisagg)
1518 0 : ereport(ERROR,
1519 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1520 : errmsg("cast function must not be an aggregate function")));
1521 3 : if (procstruct->proiswindow)
1522 0 : ereport(ERROR,
1523 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1524 : errmsg("cast function must not be a window function")));
1525 3 : if (procstruct->proretset)
1526 0 : ereport(ERROR,
1527 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1528 : errmsg("cast function must not return a set")));
1529 :
1530 3 : ReleaseSysCache(tuple);
1531 : }
1532 : else
1533 : {
1534 7 : funcid = InvalidOid;
1535 7 : nargs = 0;
1536 : }
1537 :
1538 10 : 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 6 : if (!superuser())
1552 0 : 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 6 : get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1563 6 : get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1564 12 : if (typ1len != typ2len ||
1565 12 : typ1byval != typ2byval ||
1566 6 : typ1align != typ2align)
1567 0 : 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 6 : if (sourcetyptype == TYPTYPE_COMPOSITE ||
1581 : targettyptype == TYPTYPE_COMPOSITE)
1582 0 : ereport(ERROR,
1583 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1584 : errmsg("composite data types are not binary-compatible")));
1585 :
1586 6 : if (sourcetyptype == TYPTYPE_ENUM ||
1587 : targettyptype == TYPTYPE_ENUM)
1588 0 : ereport(ERROR,
1589 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1590 : errmsg("enum data types are not binary-compatible")));
1591 :
1592 12 : if (OidIsValid(get_element_type(sourcetypeid)) ||
1593 6 : OidIsValid(get_element_type(targettypeid)))
1594 0 : 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 6 : if (sourcetyptype == TYPTYPE_DOMAIN ||
1610 : targettyptype == TYPTYPE_DOMAIN)
1611 0 : 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 10 : if (sourcetypeid == targettypeid && nargs < 2)
1621 0 : 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 10 : switch (stmt->context)
1627 : {
1628 : case COERCION_IMPLICIT:
1629 2 : castcontext = COERCION_CODE_IMPLICIT;
1630 2 : break;
1631 : case COERCION_ASSIGNMENT:
1632 1 : castcontext = COERCION_CODE_ASSIGNMENT;
1633 1 : break;
1634 : case COERCION_EXPLICIT:
1635 7 : castcontext = COERCION_CODE_EXPLICIT;
1636 7 : break;
1637 : default:
1638 0 : elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1639 : castcontext = 0; /* keep compiler quiet */
1640 : break;
1641 : }
1642 :
1643 10 : 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 10 : tuple = SearchSysCache2(CASTSOURCETARGET,
1651 : ObjectIdGetDatum(sourcetypeid),
1652 : ObjectIdGetDatum(targettypeid));
1653 10 : if (HeapTupleIsValid(tuple))
1654 0 : 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 10 : values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
1662 10 : values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
1663 10 : values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
1664 10 : values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1665 10 : values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);
1666 :
1667 10 : MemSet(nulls, false, sizeof(nulls));
1668 :
1669 10 : tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1670 :
1671 10 : castid = CatalogTupleInsert(relation, tuple);
1672 :
1673 : /* make dependency entries */
1674 10 : myself.classId = CastRelationId;
1675 10 : myself.objectId = castid;
1676 10 : myself.objectSubId = 0;
1677 :
1678 : /* dependency on source type */
1679 10 : referenced.classId = TypeRelationId;
1680 10 : referenced.objectId = sourcetypeid;
1681 10 : referenced.objectSubId = 0;
1682 10 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1683 :
1684 : /* dependency on target type */
1685 10 : referenced.classId = TypeRelationId;
1686 10 : referenced.objectId = targettypeid;
1687 10 : referenced.objectSubId = 0;
1688 10 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1689 :
1690 : /* dependency on function */
1691 10 : if (OidIsValid(funcid))
1692 : {
1693 3 : referenced.classId = ProcedureRelationId;
1694 3 : referenced.objectId = funcid;
1695 3 : referenced.objectSubId = 0;
1696 3 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1697 : }
1698 :
1699 : /* dependency on extension */
1700 10 : recordDependencyOnCurrentExtension(&myself, false);
1701 :
1702 : /* Post creation hook for new cast */
1703 10 : InvokeObjectPostCreateHook(CastRelationId, castid, 0);
1704 :
1705 10 : heap_freetuple(tuple);
1706 :
1707 10 : heap_close(relation, RowExclusiveLock);
1708 :
1709 10 : 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
1719 11 : get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
1720 : {
1721 : Oid oid;
1722 :
1723 11 : oid = GetSysCacheOid2(CASTSOURCETARGET,
1724 : ObjectIdGetDatum(sourcetypeid),
1725 : ObjectIdGetDatum(targettypeid));
1726 11 : if (!OidIsValid(oid) && !missing_ok)
1727 1 : 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 10 : return oid;
1733 : }
1734 :
1735 : void
1736 4 : DropCastById(Oid castOid)
1737 : {
1738 : Relation relation;
1739 : ScanKeyData scankey;
1740 : SysScanDesc scan;
1741 : HeapTuple tuple;
1742 :
1743 4 : relation = heap_open(CastRelationId, RowExclusiveLock);
1744 :
1745 4 : ScanKeyInit(&scankey,
1746 : ObjectIdAttributeNumber,
1747 : BTEqualStrategyNumber, F_OIDEQ,
1748 : ObjectIdGetDatum(castOid));
1749 4 : scan = systable_beginscan(relation, CastOidIndexId, true,
1750 : NULL, 1, &scankey);
1751 :
1752 4 : tuple = systable_getnext(scan);
1753 4 : if (!HeapTupleIsValid(tuple))
1754 0 : elog(ERROR, "could not find tuple for cast %u", castOid);
1755 4 : CatalogTupleDelete(relation, &tuple->t_self);
1756 :
1757 4 : systable_endscan(scan);
1758 4 : heap_close(relation, RowExclusiveLock);
1759 4 : }
1760 :
1761 :
1762 : static void
1763 2 : check_transform_function(Form_pg_proc procstruct)
1764 : {
1765 2 : if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1766 0 : ereport(ERROR,
1767 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1768 : errmsg("transform function must not be volatile")));
1769 2 : if (procstruct->proisagg)
1770 0 : ereport(ERROR,
1771 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1772 : errmsg("transform function must not be an aggregate function")));
1773 2 : if (procstruct->proiswindow)
1774 0 : ereport(ERROR,
1775 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1776 : errmsg("transform function must not be a window function")));
1777 2 : if (procstruct->proretset)
1778 0 : ereport(ERROR,
1779 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1780 : errmsg("transform function must not return a set")));
1781 2 : if (procstruct->pronargs != 1)
1782 0 : ereport(ERROR,
1783 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1784 : errmsg("transform function must take one argument")));
1785 2 : if (procstruct->proargtypes.values[0] != INTERNALOID)
1786 0 : ereport(ERROR,
1787 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1788 : errmsg("first argument of transform function must be type %s",
1789 : "internal")));
1790 2 : }
1791 :
1792 :
1793 : /*
1794 : * CREATE TRANSFORM
1795 : */
1796 : ObjectAddress
1797 1 : 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 1 : typeid = typenameTypeId(NULL, stmt->type_name);
1821 1 : typtype = get_typtype(typeid);
1822 :
1823 1 : if (typtype == TYPTYPE_PSEUDO)
1824 0 : ereport(ERROR,
1825 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1826 : errmsg("data type %s is a pseudo-type",
1827 : TypeNameToString(stmt->type_name))));
1828 :
1829 1 : if (typtype == TYPTYPE_DOMAIN)
1830 0 : ereport(ERROR,
1831 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1832 : errmsg("data type %s is a domain",
1833 : TypeNameToString(stmt->type_name))));
1834 :
1835 1 : if (!pg_type_ownercheck(typeid, GetUserId()))
1836 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
1837 :
1838 1 : aclresult = pg_type_aclcheck(typeid, GetUserId(), ACL_USAGE);
1839 1 : if (aclresult != ACLCHECK_OK)
1840 0 : aclcheck_error_type(aclresult, typeid);
1841 :
1842 : /*
1843 : * Get the language
1844 : */
1845 1 : langid = get_language_oid(stmt->lang, false);
1846 :
1847 1 : aclresult = pg_language_aclcheck(langid, GetUserId(), ACL_USAGE);
1848 1 : if (aclresult != ACLCHECK_OK)
1849 0 : aclcheck_error(aclresult, ACL_KIND_LANGUAGE, stmt->lang);
1850 :
1851 : /*
1852 : * Get the functions
1853 : */
1854 1 : if (stmt->fromsql)
1855 : {
1856 1 : fromsqlfuncid = LookupFuncWithArgs(stmt->fromsql, false);
1857 :
1858 1 : if (!pg_proc_ownercheck(fromsqlfuncid, GetUserId()))
1859 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->fromsql->objname));
1860 :
1861 1 : aclresult = pg_proc_aclcheck(fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1862 1 : if (aclresult != ACLCHECK_OK)
1863 0 : aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(stmt->fromsql->objname));
1864 :
1865 1 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1866 1 : if (!HeapTupleIsValid(tuple))
1867 0 : elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1868 1 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1869 1 : if (procstruct->prorettype != INTERNALOID)
1870 0 : ereport(ERROR,
1871 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1872 : errmsg("return data type of FROM SQL function must be %s",
1873 : "internal")));
1874 1 : check_transform_function(procstruct);
1875 1 : ReleaseSysCache(tuple);
1876 : }
1877 : else
1878 0 : fromsqlfuncid = InvalidOid;
1879 :
1880 1 : if (stmt->tosql)
1881 : {
1882 1 : tosqlfuncid = LookupFuncWithArgs(stmt->tosql, false);
1883 :
1884 1 : if (!pg_proc_ownercheck(tosqlfuncid, GetUserId()))
1885 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->tosql->objname));
1886 :
1887 1 : aclresult = pg_proc_aclcheck(tosqlfuncid, GetUserId(), ACL_EXECUTE);
1888 1 : if (aclresult != ACLCHECK_OK)
1889 0 : aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(stmt->tosql->objname));
1890 :
1891 1 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1892 1 : if (!HeapTupleIsValid(tuple))
1893 0 : elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1894 1 : procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1895 1 : if (procstruct->prorettype != typeid)
1896 0 : ereport(ERROR,
1897 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1898 : errmsg("return data type of TO SQL function must be the transform data type")));
1899 1 : check_transform_function(procstruct);
1900 1 : ReleaseSysCache(tuple);
1901 : }
1902 : else
1903 0 : tosqlfuncid = InvalidOid;
1904 :
1905 : /*
1906 : * Ready to go
1907 : */
1908 1 : values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1909 1 : values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1910 1 : values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1911 1 : values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1912 :
1913 1 : MemSet(nulls, false, sizeof(nulls));
1914 :
1915 1 : relation = heap_open(TransformRelationId, RowExclusiveLock);
1916 :
1917 1 : tuple = SearchSysCache2(TRFTYPELANG,
1918 : ObjectIdGetDatum(typeid),
1919 : ObjectIdGetDatum(langid));
1920 1 : if (HeapTupleIsValid(tuple))
1921 : {
1922 0 : if (!stmt->replace)
1923 0 : 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 0 : MemSet(replaces, false, sizeof(replaces));
1930 0 : replaces[Anum_pg_transform_trffromsql - 1] = true;
1931 0 : replaces[Anum_pg_transform_trftosql - 1] = true;
1932 :
1933 0 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1934 0 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1935 :
1936 0 : transformid = HeapTupleGetOid(tuple);
1937 0 : ReleaseSysCache(tuple);
1938 0 : is_replace = true;
1939 : }
1940 : else
1941 : {
1942 1 : newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1943 1 : transformid = CatalogTupleInsert(relation, newtuple);
1944 1 : is_replace = false;
1945 : }
1946 :
1947 1 : if (is_replace)
1948 0 : deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1949 :
1950 : /* make dependency entries */
1951 1 : myself.classId = TransformRelationId;
1952 1 : myself.objectId = transformid;
1953 1 : myself.objectSubId = 0;
1954 :
1955 : /* dependency on language */
1956 1 : referenced.classId = LanguageRelationId;
1957 1 : referenced.objectId = langid;
1958 1 : referenced.objectSubId = 0;
1959 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1960 :
1961 : /* dependency on type */
1962 1 : referenced.classId = TypeRelationId;
1963 1 : referenced.objectId = typeid;
1964 1 : referenced.objectSubId = 0;
1965 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1966 :
1967 : /* dependencies on functions */
1968 1 : if (OidIsValid(fromsqlfuncid))
1969 : {
1970 1 : referenced.classId = ProcedureRelationId;
1971 1 : referenced.objectId = fromsqlfuncid;
1972 1 : referenced.objectSubId = 0;
1973 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1974 : }
1975 1 : if (OidIsValid(tosqlfuncid))
1976 : {
1977 1 : referenced.classId = ProcedureRelationId;
1978 1 : referenced.objectId = tosqlfuncid;
1979 1 : referenced.objectSubId = 0;
1980 1 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1981 : }
1982 :
1983 : /* dependency on extension */
1984 1 : recordDependencyOnCurrentExtension(&myself, is_replace);
1985 :
1986 : /* Post creation hook for new transform */
1987 1 : InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
1988 :
1989 1 : heap_freetuple(newtuple);
1990 :
1991 1 : heap_close(relation, RowExclusiveLock);
1992 :
1993 1 : 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
2004 2232 : get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
2005 : {
2006 : Oid oid;
2007 :
2008 2232 : oid = GetSysCacheOid2(TRFTYPELANG,
2009 : ObjectIdGetDatum(type_id),
2010 : ObjectIdGetDatum(lang_id));
2011 2232 : if (!OidIsValid(oid) && !missing_ok)
2012 0 : 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 2232 : return oid;
2018 : }
2019 :
2020 :
2021 : void
2022 0 : DropTransformById(Oid transformOid)
2023 : {
2024 : Relation relation;
2025 : ScanKeyData scankey;
2026 : SysScanDesc scan;
2027 : HeapTuple tuple;
2028 :
2029 0 : relation = heap_open(TransformRelationId, RowExclusiveLock);
2030 :
2031 0 : ScanKeyInit(&scankey,
2032 : ObjectIdAttributeNumber,
2033 : BTEqualStrategyNumber, F_OIDEQ,
2034 : ObjectIdGetDatum(transformOid));
2035 0 : scan = systable_beginscan(relation, TransformOidIndexId, true,
2036 : NULL, 1, &scankey);
2037 :
2038 0 : tuple = systable_getnext(scan);
2039 0 : if (!HeapTupleIsValid(tuple))
2040 0 : elog(ERROR, "could not find tuple for transform %u", transformOid);
2041 0 : CatalogTupleDelete(relation, &tuple->t_self);
2042 :
2043 0 : systable_endscan(scan);
2044 0 : heap_close(relation, RowExclusiveLock);
2045 0 : }
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
2055 14 : IsThereFunctionInNamespace(const char *proname, int pronargs,
2056 : oidvector *proargtypes, Oid nspOid)
2057 : {
2058 : /* check for duplicate name (more friendly than unique-index failure) */
2059 14 : if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2060 : CStringGetDatum(proname),
2061 : PointerGetDatum(proargtypes),
2062 : ObjectIdGetDatum(nspOid)))
2063 4 : 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 10 : }
2070 :
2071 : /*
2072 : * ExecuteDoStmt
2073 : * Execute inline procedural-language code
2074 : */
2075 : void
2076 40 : ExecuteDoStmt(DoStmt *stmt)
2077 : {
2078 40 : InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
2079 : ListCell *arg;
2080 40 : DefElem *as_item = NULL;
2081 40 : 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 82 : foreach(arg, stmt->args)
2089 : {
2090 42 : DefElem *defel = (DefElem *) lfirst(arg);
2091 :
2092 42 : if (strcmp(defel->defname, "as") == 0)
2093 : {
2094 40 : if (as_item)
2095 0 : ereport(ERROR,
2096 : (errcode(ERRCODE_SYNTAX_ERROR),
2097 : errmsg("conflicting or redundant options")));
2098 40 : as_item = defel;
2099 : }
2100 2 : else if (strcmp(defel->defname, "language") == 0)
2101 : {
2102 2 : if (language_item)
2103 0 : ereport(ERROR,
2104 : (errcode(ERRCODE_SYNTAX_ERROR),
2105 : errmsg("conflicting or redundant options")));
2106 2 : language_item = defel;
2107 : }
2108 : else
2109 0 : elog(ERROR, "option \"%s\" not recognized",
2110 : defel->defname);
2111 : }
2112 :
2113 40 : if (as_item)
2114 40 : codeblock->source_text = strVal(as_item->arg);
2115 : else
2116 0 : 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 40 : if (language_item)
2122 2 : language = strVal(language_item->arg);
2123 : else
2124 38 : language = "plpgsql";
2125 :
2126 : /* Look up the language and validate permissions */
2127 40 : languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2128 40 : if (!HeapTupleIsValid(languageTuple))
2129 0 : 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 40 : codeblock->langOid = HeapTupleGetOid(languageTuple);
2136 40 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2137 40 : codeblock->langIsTrusted = languageStruct->lanpltrusted;
2138 :
2139 40 : if (languageStruct->lanpltrusted)
2140 : {
2141 : /* if trusted language, need USAGE privilege */
2142 : AclResult aclresult;
2143 :
2144 40 : aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
2145 : ACL_USAGE);
2146 40 : if (aclresult != ACLCHECK_OK)
2147 0 : aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
2148 0 : NameStr(languageStruct->lanname));
2149 : }
2150 : else
2151 : {
2152 : /* if untrusted language, must be superuser */
2153 0 : if (!superuser())
2154 0 : aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
2155 0 : NameStr(languageStruct->lanname));
2156 : }
2157 :
2158 : /* get the handler function's OID */
2159 40 : laninline = languageStruct->laninline;
2160 40 : if (!OidIsValid(laninline))
2161 0 : ereport(ERROR,
2162 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2163 : errmsg("language \"%s\" does not support inline code execution",
2164 : NameStr(languageStruct->lanname))));
2165 :
2166 40 : ReleaseSysCache(languageTuple);
2167 :
2168 : /* execute the inline handler */
2169 40 : OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2170 19 : }
|