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