1 /*-------------------------------------------------------------------------
2  *
3  * funcapi.c
4  *	  Utility and convenience functions for fmgr functions that return
5  *	  sets and/or composite types, or deal with VARIADIC inputs.
6  *
7  * Copyright (c) 2002-2019, PostgreSQL Global Development Group
8  *
9  * IDENTIFICATION
10  *	  src/backend/utils/fmgr/funcapi.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/htup_details.h"
17 #include "access/relation.h"
18 #include "catalog/namespace.h"
19 #include "catalog/pg_proc.h"
20 #include "catalog/pg_type.h"
21 #include "funcapi.h"
22 #include "nodes/nodeFuncs.h"
23 #include "utils/array.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/memutils.h"
27 #include "utils/regproc.h"
28 #include "utils/rel.h"
29 #include "utils/syscache.h"
30 #include "utils/typcache.h"
31 
32 
33 typedef struct polymorphic_actuals
34 {
35 	Oid			anyelement_type;	/* anyelement mapping, if known */
36 	Oid			anyarray_type;	/* anyarray mapping, if known */
37 	Oid			anyrange_type;	/* anyrange mapping, if known */
38 } polymorphic_actuals;
39 
40 static void shutdown_MultiFuncCall(Datum arg);
41 static TypeFuncClass internal_get_result_type(Oid funcid,
42 											  Node *call_expr,
43 											  ReturnSetInfo *rsinfo,
44 											  Oid *resultTypeId,
45 											  TupleDesc *resultTupleDesc);
46 static void resolve_anyelement_from_others(polymorphic_actuals *actuals);
47 static void resolve_anyarray_from_others(polymorphic_actuals *actuals);
48 static void resolve_anyrange_from_others(polymorphic_actuals *actuals);
49 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
50 										oidvector *declared_args,
51 										Node *call_expr);
52 static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
53 
54 
55 /*
56  * init_MultiFuncCall
57  * Create an empty FuncCallContext data structure
58  * and do some other basic Multi-function call setup
59  * and error checking
60  */
61 FuncCallContext *
init_MultiFuncCall(PG_FUNCTION_ARGS)62 init_MultiFuncCall(PG_FUNCTION_ARGS)
63 {
64 	FuncCallContext *retval;
65 
66 	/*
67 	 * Bail if we're called in the wrong context
68 	 */
69 	if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
70 		ereport(ERROR,
71 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
72 				 errmsg("set-valued function called in context that cannot accept a set")));
73 
74 	if (fcinfo->flinfo->fn_extra == NULL)
75 	{
76 		/*
77 		 * First call
78 		 */
79 		ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
80 		MemoryContext multi_call_ctx;
81 
82 		/*
83 		 * Create a suitably long-lived context to hold cross-call data
84 		 */
85 		multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
86 											   "SRF multi-call context",
87 											   ALLOCSET_SMALL_SIZES);
88 
89 		/*
90 		 * Allocate suitably long-lived space and zero it
91 		 */
92 		retval = (FuncCallContext *)
93 			MemoryContextAllocZero(multi_call_ctx,
94 								   sizeof(FuncCallContext));
95 
96 		/*
97 		 * initialize the elements
98 		 */
99 		retval->call_cntr = 0;
100 		retval->max_calls = 0;
101 		retval->user_fctx = NULL;
102 		retval->attinmeta = NULL;
103 		retval->tuple_desc = NULL;
104 		retval->multi_call_memory_ctx = multi_call_ctx;
105 
106 		/*
107 		 * save the pointer for cross-call use
108 		 */
109 		fcinfo->flinfo->fn_extra = retval;
110 
111 		/*
112 		 * Ensure we will get shut down cleanly if the exprcontext is not run
113 		 * to completion.
114 		 */
115 		RegisterExprContextCallback(rsi->econtext,
116 									shutdown_MultiFuncCall,
117 									PointerGetDatum(fcinfo->flinfo));
118 	}
119 	else
120 	{
121 		/* second and subsequent calls */
122 		elog(ERROR, "init_MultiFuncCall cannot be called more than once");
123 
124 		/* never reached, but keep compiler happy */
125 		retval = NULL;
126 	}
127 
128 	return retval;
129 }
130 
131 /*
132  * per_MultiFuncCall
133  *
134  * Do Multi-function per-call setup
135  */
136 FuncCallContext *
per_MultiFuncCall(PG_FUNCTION_ARGS)137 per_MultiFuncCall(PG_FUNCTION_ARGS)
138 {
139 	FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
140 
141 	return retval;
142 }
143 
144 /*
145  * end_MultiFuncCall
146  * Clean up after init_MultiFuncCall
147  */
148 void
end_MultiFuncCall(PG_FUNCTION_ARGS,FuncCallContext * funcctx)149 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
150 {
151 	ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
152 
153 	/* Deregister the shutdown callback */
154 	UnregisterExprContextCallback(rsi->econtext,
155 								  shutdown_MultiFuncCall,
156 								  PointerGetDatum(fcinfo->flinfo));
157 
158 	/* But use it to do the real work */
159 	shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
160 }
161 
162 /*
163  * shutdown_MultiFuncCall
164  * Shutdown function to clean up after init_MultiFuncCall
165  */
166 static void
shutdown_MultiFuncCall(Datum arg)167 shutdown_MultiFuncCall(Datum arg)
168 {
169 	FmgrInfo   *flinfo = (FmgrInfo *) DatumGetPointer(arg);
170 	FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
171 
172 	/* unbind from flinfo */
173 	flinfo->fn_extra = NULL;
174 
175 	/*
176 	 * Delete context that holds all multi-call data, including the
177 	 * FuncCallContext itself
178 	 */
179 	MemoryContextDelete(funcctx->multi_call_memory_ctx);
180 }
181 
182 
183 /*
184  * get_call_result_type
185  *		Given a function's call info record, determine the kind of datatype
186  *		it is supposed to return.  If resultTypeId isn't NULL, *resultTypeId
187  *		receives the actual datatype OID (this is mainly useful for scalar
188  *		result types).  If resultTupleDesc isn't NULL, *resultTupleDesc
189  *		receives a pointer to a TupleDesc when the result is of a composite
190  *		type, or NULL when it's a scalar result.
191  *
192  * One hard case that this handles is resolution of actual rowtypes for
193  * functions returning RECORD (from either the function's OUT parameter
194  * list, or a ReturnSetInfo context node).  TYPEFUNC_RECORD is returned
195  * only when we couldn't resolve the actual rowtype for lack of information.
196  *
197  * The other hard case that this handles is resolution of polymorphism.
198  * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
199  * as a scalar result type or as a component of a rowtype.
200  *
201  * This function is relatively expensive --- in a function returning set,
202  * try to call it only the first time through.
203  */
204 TypeFuncClass
get_call_result_type(FunctionCallInfo fcinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)205 get_call_result_type(FunctionCallInfo fcinfo,
206 					 Oid *resultTypeId,
207 					 TupleDesc *resultTupleDesc)
208 {
209 	return internal_get_result_type(fcinfo->flinfo->fn_oid,
210 									fcinfo->flinfo->fn_expr,
211 									(ReturnSetInfo *) fcinfo->resultinfo,
212 									resultTypeId,
213 									resultTupleDesc);
214 }
215 
216 /*
217  * get_expr_result_type
218  *		As above, but work from a calling expression node tree
219  */
220 TypeFuncClass
get_expr_result_type(Node * expr,Oid * resultTypeId,TupleDesc * resultTupleDesc)221 get_expr_result_type(Node *expr,
222 					 Oid *resultTypeId,
223 					 TupleDesc *resultTupleDesc)
224 {
225 	TypeFuncClass result;
226 
227 	if (expr && IsA(expr, FuncExpr))
228 		result = internal_get_result_type(((FuncExpr *) expr)->funcid,
229 										  expr,
230 										  NULL,
231 										  resultTypeId,
232 										  resultTupleDesc);
233 	else if (expr && IsA(expr, OpExpr))
234 		result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
235 										  expr,
236 										  NULL,
237 										  resultTypeId,
238 										  resultTupleDesc);
239 	else
240 	{
241 		/* handle as a generic expression; no chance to resolve RECORD */
242 		Oid			typid = exprType(expr);
243 		Oid			base_typid;
244 
245 		if (resultTypeId)
246 			*resultTypeId = typid;
247 		if (resultTupleDesc)
248 			*resultTupleDesc = NULL;
249 		result = get_type_func_class(typid, &base_typid);
250 		if ((result == TYPEFUNC_COMPOSITE ||
251 			 result == TYPEFUNC_COMPOSITE_DOMAIN) &&
252 			resultTupleDesc)
253 			*resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
254 	}
255 
256 	return result;
257 }
258 
259 /*
260  * get_func_result_type
261  *		As above, but work from a function's OID only
262  *
263  * This will not be able to resolve pure-RECORD results nor polymorphism.
264  */
265 TypeFuncClass
get_func_result_type(Oid functionId,Oid * resultTypeId,TupleDesc * resultTupleDesc)266 get_func_result_type(Oid functionId,
267 					 Oid *resultTypeId,
268 					 TupleDesc *resultTupleDesc)
269 {
270 	return internal_get_result_type(functionId,
271 									NULL,
272 									NULL,
273 									resultTypeId,
274 									resultTupleDesc);
275 }
276 
277 /*
278  * internal_get_result_type -- workhorse code implementing all the above
279  *
280  * funcid must always be supplied.  call_expr and rsinfo can be NULL if not
281  * available.  We will return TYPEFUNC_RECORD, and store NULL into
282  * *resultTupleDesc, if we cannot deduce the complete result rowtype from
283  * the available information.
284  */
285 static TypeFuncClass
internal_get_result_type(Oid funcid,Node * call_expr,ReturnSetInfo * rsinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)286 internal_get_result_type(Oid funcid,
287 						 Node *call_expr,
288 						 ReturnSetInfo *rsinfo,
289 						 Oid *resultTypeId,
290 						 TupleDesc *resultTupleDesc)
291 {
292 	TypeFuncClass result;
293 	HeapTuple	tp;
294 	Form_pg_proc procform;
295 	Oid			rettype;
296 	Oid			base_rettype;
297 	TupleDesc	tupdesc;
298 
299 	/* First fetch the function's pg_proc row to inspect its rettype */
300 	tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
301 	if (!HeapTupleIsValid(tp))
302 		elog(ERROR, "cache lookup failed for function %u", funcid);
303 	procform = (Form_pg_proc) GETSTRUCT(tp);
304 
305 	rettype = procform->prorettype;
306 
307 	/* Check for OUT parameters defining a RECORD result */
308 	tupdesc = build_function_result_tupdesc_t(tp);
309 	if (tupdesc)
310 	{
311 		/*
312 		 * It has OUT parameters, so it's basically like a regular composite
313 		 * type, except we have to be able to resolve any polymorphic OUT
314 		 * parameters.
315 		 */
316 		if (resultTypeId)
317 			*resultTypeId = rettype;
318 
319 		if (resolve_polymorphic_tupdesc(tupdesc,
320 										&procform->proargtypes,
321 										call_expr))
322 		{
323 			if (tupdesc->tdtypeid == RECORDOID &&
324 				tupdesc->tdtypmod < 0)
325 				assign_record_type_typmod(tupdesc);
326 			if (resultTupleDesc)
327 				*resultTupleDesc = tupdesc;
328 			result = TYPEFUNC_COMPOSITE;
329 		}
330 		else
331 		{
332 			if (resultTupleDesc)
333 				*resultTupleDesc = NULL;
334 			result = TYPEFUNC_RECORD;
335 		}
336 
337 		ReleaseSysCache(tp);
338 
339 		return result;
340 	}
341 
342 	/*
343 	 * If scalar polymorphic result, try to resolve it.
344 	 */
345 	if (IsPolymorphicType(rettype))
346 	{
347 		Oid			newrettype = exprType(call_expr);
348 
349 		if (newrettype == InvalidOid)	/* this probably should not happen */
350 			ereport(ERROR,
351 					(errcode(ERRCODE_DATATYPE_MISMATCH),
352 					 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
353 							NameStr(procform->proname),
354 							format_type_be(rettype))));
355 		rettype = newrettype;
356 	}
357 
358 	if (resultTypeId)
359 		*resultTypeId = rettype;
360 	if (resultTupleDesc)
361 		*resultTupleDesc = NULL;	/* default result */
362 
363 	/* Classify the result type */
364 	result = get_type_func_class(rettype, &base_rettype);
365 	switch (result)
366 	{
367 		case TYPEFUNC_COMPOSITE:
368 		case TYPEFUNC_COMPOSITE_DOMAIN:
369 			if (resultTupleDesc)
370 				*resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
371 			/* Named composite types can't have any polymorphic columns */
372 			break;
373 		case TYPEFUNC_SCALAR:
374 			break;
375 		case TYPEFUNC_RECORD:
376 			/* We must get the tupledesc from call context */
377 			if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
378 				rsinfo->expectedDesc != NULL)
379 			{
380 				result = TYPEFUNC_COMPOSITE;
381 				if (resultTupleDesc)
382 					*resultTupleDesc = rsinfo->expectedDesc;
383 				/* Assume no polymorphic columns here, either */
384 			}
385 			break;
386 		default:
387 			break;
388 	}
389 
390 	ReleaseSysCache(tp);
391 
392 	return result;
393 }
394 
395 /*
396  * get_expr_result_tupdesc
397  *		Get a tupdesc describing the result of a composite-valued expression
398  *
399  * If expression is not composite or rowtype can't be determined, returns NULL
400  * if noError is true, else throws error.
401  *
402  * This is a simpler version of get_expr_result_type() for use when the caller
403  * is only interested in determinate rowtype results.
404  */
405 TupleDesc
get_expr_result_tupdesc(Node * expr,bool noError)406 get_expr_result_tupdesc(Node *expr, bool noError)
407 {
408 	TupleDesc	tupleDesc;
409 	TypeFuncClass functypclass;
410 
411 	functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
412 
413 	if (functypclass == TYPEFUNC_COMPOSITE ||
414 		functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
415 		return tupleDesc;
416 
417 	if (!noError)
418 	{
419 		Oid			exprTypeId = exprType(expr);
420 
421 		if (exprTypeId != RECORDOID)
422 			ereport(ERROR,
423 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
424 					 errmsg("type %s is not composite",
425 							format_type_be(exprTypeId))));
426 		else
427 			ereport(ERROR,
428 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
429 					 errmsg("record type has not been registered")));
430 	}
431 
432 	return NULL;
433 }
434 
435 /*
436  * Resolve actual type of ANYELEMENT from other polymorphic inputs
437  *
438  * Note: the error cases here and in the sibling functions below are not
439  * really user-facing; they could only occur if the function signature is
440  * incorrect or the parser failed to enforce consistency of the actual
441  * argument types.  Hence, we don't sweat too much over the error messages.
442  */
443 static void
resolve_anyelement_from_others(polymorphic_actuals * actuals)444 resolve_anyelement_from_others(polymorphic_actuals *actuals)
445 {
446 	if (OidIsValid(actuals->anyarray_type))
447 	{
448 		/* Use the element type corresponding to actual type */
449 		Oid			array_base_type = getBaseType(actuals->anyarray_type);
450 		Oid			array_typelem = get_element_type(array_base_type);
451 
452 		if (!OidIsValid(array_typelem))
453 			ereport(ERROR,
454 					(errcode(ERRCODE_DATATYPE_MISMATCH),
455 					 errmsg("argument declared %s is not an array but type %s",
456 							"anyarray",
457 							format_type_be(array_base_type))));
458 		actuals->anyelement_type = array_typelem;
459 	}
460 	else if (OidIsValid(actuals->anyrange_type))
461 	{
462 		/* Use the element type corresponding to actual type */
463 		Oid			range_base_type = getBaseType(actuals->anyrange_type);
464 		Oid			range_typelem = get_range_subtype(range_base_type);
465 
466 		if (!OidIsValid(range_typelem))
467 			ereport(ERROR,
468 					(errcode(ERRCODE_DATATYPE_MISMATCH),
469 					 errmsg("argument declared %s is not a range type but type %s",
470 							"anyrange",
471 							format_type_be(range_base_type))));
472 		actuals->anyelement_type = range_typelem;
473 	}
474 	else
475 		elog(ERROR, "could not determine polymorphic type");
476 }
477 
478 /*
479  * Resolve actual type of ANYARRAY from other polymorphic inputs
480  */
481 static void
resolve_anyarray_from_others(polymorphic_actuals * actuals)482 resolve_anyarray_from_others(polymorphic_actuals *actuals)
483 {
484 	/* If we don't know ANYELEMENT, resolve that first */
485 	if (!OidIsValid(actuals->anyelement_type))
486 		resolve_anyelement_from_others(actuals);
487 
488 	if (OidIsValid(actuals->anyelement_type))
489 	{
490 		/* Use the array type corresponding to actual type */
491 		Oid			array_typeid = get_array_type(actuals->anyelement_type);
492 
493 		if (!OidIsValid(array_typeid))
494 			ereport(ERROR,
495 					(errcode(ERRCODE_UNDEFINED_OBJECT),
496 					 errmsg("could not find array type for data type %s",
497 							format_type_be(actuals->anyelement_type))));
498 		actuals->anyarray_type = array_typeid;
499 	}
500 	else
501 		elog(ERROR, "could not determine polymorphic type");
502 }
503 
504 /*
505  * Resolve actual type of ANYRANGE from other polymorphic inputs
506  */
507 static void
resolve_anyrange_from_others(polymorphic_actuals * actuals)508 resolve_anyrange_from_others(polymorphic_actuals *actuals)
509 {
510 	/*
511 	 * We can't deduce a range type from other polymorphic inputs, because
512 	 * there may be multiple range types with the same subtype.
513 	 */
514 	elog(ERROR, "could not determine polymorphic type");
515 }
516 
517 /*
518  * Given the result tuple descriptor for a function with OUT parameters,
519  * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
520  * with concrete data types deduced from the input arguments.
521  * declared_args is an oidvector of the function's declared input arg types
522  * (showing which are polymorphic), and call_expr is the call expression.
523  * Returns true if able to deduce all types, false if not.
524  */
525 static bool
resolve_polymorphic_tupdesc(TupleDesc tupdesc,oidvector * declared_args,Node * call_expr)526 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
527 							Node *call_expr)
528 {
529 	int			natts = tupdesc->natts;
530 	int			nargs = declared_args->dim1;
531 	bool		have_polymorphic_result = false;
532 	bool		have_anyelement_result = false;
533 	bool		have_anyarray_result = false;
534 	bool		have_anyrange_result = false;
535 	polymorphic_actuals poly_actuals;
536 	Oid			anycollation = InvalidOid;
537 	int			i;
538 
539 	/* See if there are any polymorphic outputs; quick out if not */
540 	for (i = 0; i < natts; i++)
541 	{
542 		switch (TupleDescAttr(tupdesc, i)->atttypid)
543 		{
544 			case ANYELEMENTOID:
545 			case ANYNONARRAYOID:
546 			case ANYENUMOID:
547 				have_polymorphic_result = true;
548 				have_anyelement_result = true;
549 				break;
550 			case ANYARRAYOID:
551 				have_polymorphic_result = true;
552 				have_anyarray_result = true;
553 				break;
554 			case ANYRANGEOID:
555 				have_polymorphic_result = true;
556 				have_anyrange_result = true;
557 				break;
558 			default:
559 				break;
560 		}
561 	}
562 	if (!have_polymorphic_result)
563 		return true;
564 
565 	/*
566 	 * Otherwise, extract actual datatype(s) from input arguments.  (We assume
567 	 * the parser already validated consistency of the arguments.)
568 	 */
569 	if (!call_expr)
570 		return false;			/* no hope */
571 
572 	memset(&poly_actuals, 0, sizeof(poly_actuals));
573 
574 	for (i = 0; i < nargs; i++)
575 	{
576 		switch (declared_args->values[i])
577 		{
578 			case ANYELEMENTOID:
579 			case ANYNONARRAYOID:
580 			case ANYENUMOID:
581 				if (!OidIsValid(poly_actuals.anyelement_type))
582 				{
583 					poly_actuals.anyelement_type =
584 						get_call_expr_argtype(call_expr, i);
585 					if (!OidIsValid(poly_actuals.anyelement_type))
586 						return false;
587 				}
588 				break;
589 			case ANYARRAYOID:
590 				if (!OidIsValid(poly_actuals.anyarray_type))
591 				{
592 					poly_actuals.anyarray_type =
593 						get_call_expr_argtype(call_expr, i);
594 					if (!OidIsValid(poly_actuals.anyarray_type))
595 						return false;
596 				}
597 				break;
598 			case ANYRANGEOID:
599 				if (!OidIsValid(poly_actuals.anyrange_type))
600 				{
601 					poly_actuals.anyrange_type =
602 						get_call_expr_argtype(call_expr, i);
603 					if (!OidIsValid(poly_actuals.anyrange_type))
604 						return false;
605 				}
606 				break;
607 			default:
608 				break;
609 		}
610 	}
611 
612 	/* If needed, deduce one polymorphic type from others */
613 	if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
614 		resolve_anyelement_from_others(&poly_actuals);
615 
616 	if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
617 		resolve_anyarray_from_others(&poly_actuals);
618 
619 	if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
620 		resolve_anyrange_from_others(&poly_actuals);
621 
622 	/*
623 	 * Identify the collation to use for polymorphic OUT parameters. (It'll
624 	 * necessarily be the same for both anyelement and anyarray.)  Note that
625 	 * range types are not collatable, so any possible internal collation of a
626 	 * range type is not considered here.
627 	 */
628 	if (OidIsValid(poly_actuals.anyelement_type))
629 		anycollation = get_typcollation(poly_actuals.anyelement_type);
630 	else if (OidIsValid(poly_actuals.anyarray_type))
631 		anycollation = get_typcollation(poly_actuals.anyarray_type);
632 
633 	if (OidIsValid(anycollation))
634 	{
635 		/*
636 		 * The types are collatable, so consider whether to use a nondefault
637 		 * collation.  We do so if we can identify the input collation used
638 		 * for the function.
639 		 */
640 		Oid			inputcollation = exprInputCollation(call_expr);
641 
642 		if (OidIsValid(inputcollation))
643 			anycollation = inputcollation;
644 	}
645 
646 	/* And finally replace the tuple column types as needed */
647 	for (i = 0; i < natts; i++)
648 	{
649 		Form_pg_attribute att = TupleDescAttr(tupdesc, i);
650 
651 		switch (att->atttypid)
652 		{
653 			case ANYELEMENTOID:
654 			case ANYNONARRAYOID:
655 			case ANYENUMOID:
656 				TupleDescInitEntry(tupdesc, i + 1,
657 								   NameStr(att->attname),
658 								   poly_actuals.anyelement_type,
659 								   -1,
660 								   0);
661 				TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
662 				break;
663 			case ANYARRAYOID:
664 				TupleDescInitEntry(tupdesc, i + 1,
665 								   NameStr(att->attname),
666 								   poly_actuals.anyarray_type,
667 								   -1,
668 								   0);
669 				TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
670 				break;
671 			case ANYRANGEOID:
672 				TupleDescInitEntry(tupdesc, i + 1,
673 								   NameStr(att->attname),
674 								   poly_actuals.anyrange_type,
675 								   -1,
676 								   0);
677 				/* no collation should be attached to a range type */
678 				break;
679 			default:
680 				break;
681 		}
682 	}
683 
684 	return true;
685 }
686 
687 /*
688  * Given the declared argument types and modes for a function, replace any
689  * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
690  * deduced from the input arguments found in call_expr.
691  * Returns true if able to deduce all types, false if not.
692  *
693  * This is the same logic as resolve_polymorphic_tupdesc, but with a different
694  * argument representation, and slightly different output responsibilities.
695  *
696  * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
697  */
698 bool
resolve_polymorphic_argtypes(int numargs,Oid * argtypes,char * argmodes,Node * call_expr)699 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
700 							 Node *call_expr)
701 {
702 	bool		have_polymorphic_result = false;
703 	bool		have_anyelement_result = false;
704 	bool		have_anyarray_result = false;
705 	bool		have_anyrange_result = false;
706 	polymorphic_actuals poly_actuals;
707 	int			inargno;
708 	int			i;
709 
710 	/*
711 	 * First pass: resolve polymorphic inputs, check for outputs.  As in
712 	 * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
713 	 * type consistency.
714 	 */
715 	memset(&poly_actuals, 0, sizeof(poly_actuals));
716 	inargno = 0;
717 	for (i = 0; i < numargs; i++)
718 	{
719 		char		argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
720 
721 		switch (argtypes[i])
722 		{
723 			case ANYELEMENTOID:
724 			case ANYNONARRAYOID:
725 			case ANYENUMOID:
726 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
727 				{
728 					have_polymorphic_result = true;
729 					have_anyelement_result = true;
730 				}
731 				else
732 				{
733 					if (!OidIsValid(poly_actuals.anyelement_type))
734 					{
735 						poly_actuals.anyelement_type =
736 							get_call_expr_argtype(call_expr, inargno);
737 						if (!OidIsValid(poly_actuals.anyelement_type))
738 							return false;
739 					}
740 					argtypes[i] = poly_actuals.anyelement_type;
741 				}
742 				break;
743 			case ANYARRAYOID:
744 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
745 				{
746 					have_polymorphic_result = true;
747 					have_anyarray_result = true;
748 				}
749 				else
750 				{
751 					if (!OidIsValid(poly_actuals.anyarray_type))
752 					{
753 						poly_actuals.anyarray_type =
754 							get_call_expr_argtype(call_expr, inargno);
755 						if (!OidIsValid(poly_actuals.anyarray_type))
756 							return false;
757 					}
758 					argtypes[i] = poly_actuals.anyarray_type;
759 				}
760 				break;
761 			case ANYRANGEOID:
762 				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
763 				{
764 					have_polymorphic_result = true;
765 					have_anyrange_result = true;
766 				}
767 				else
768 				{
769 					if (!OidIsValid(poly_actuals.anyrange_type))
770 					{
771 						poly_actuals.anyrange_type =
772 							get_call_expr_argtype(call_expr, inargno);
773 						if (!OidIsValid(poly_actuals.anyrange_type))
774 							return false;
775 					}
776 					argtypes[i] = poly_actuals.anyrange_type;
777 				}
778 				break;
779 			default:
780 				break;
781 		}
782 		if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
783 			inargno++;
784 	}
785 
786 	/* Done? */
787 	if (!have_polymorphic_result)
788 		return true;
789 
790 	/* If needed, deduce one polymorphic type from others */
791 	if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
792 		resolve_anyelement_from_others(&poly_actuals);
793 
794 	if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
795 		resolve_anyarray_from_others(&poly_actuals);
796 
797 	if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
798 		resolve_anyrange_from_others(&poly_actuals);
799 
800 	/* And finally replace the output column types as needed */
801 	for (i = 0; i < numargs; i++)
802 	{
803 		switch (argtypes[i])
804 		{
805 			case ANYELEMENTOID:
806 			case ANYNONARRAYOID:
807 			case ANYENUMOID:
808 				argtypes[i] = poly_actuals.anyelement_type;
809 				break;
810 			case ANYARRAYOID:
811 				argtypes[i] = poly_actuals.anyarray_type;
812 				break;
813 			case ANYRANGEOID:
814 				argtypes[i] = poly_actuals.anyrange_type;
815 				break;
816 			default:
817 				break;
818 		}
819 	}
820 
821 	return true;
822 }
823 
824 /*
825  * get_type_func_class
826  *		Given the type OID, obtain its TYPEFUNC classification.
827  *		Also, if it's a domain, return the base type OID.
828  *
829  * This is intended to centralize a bunch of formerly ad-hoc code for
830  * classifying types.  The categories used here are useful for deciding
831  * how to handle functions returning the datatype.
832  */
833 static TypeFuncClass
get_type_func_class(Oid typid,Oid * base_typeid)834 get_type_func_class(Oid typid, Oid *base_typeid)
835 {
836 	*base_typeid = typid;
837 
838 	switch (get_typtype(typid))
839 	{
840 		case TYPTYPE_COMPOSITE:
841 			return TYPEFUNC_COMPOSITE;
842 		case TYPTYPE_BASE:
843 		case TYPTYPE_ENUM:
844 		case TYPTYPE_RANGE:
845 			return TYPEFUNC_SCALAR;
846 		case TYPTYPE_DOMAIN:
847 			*base_typeid = typid = getBaseType(typid);
848 			if (get_typtype(typid) == TYPTYPE_COMPOSITE)
849 				return TYPEFUNC_COMPOSITE_DOMAIN;
850 			else				/* domain base type can't be a pseudotype */
851 				return TYPEFUNC_SCALAR;
852 		case TYPTYPE_PSEUDO:
853 			if (typid == RECORDOID)
854 				return TYPEFUNC_RECORD;
855 
856 			/*
857 			 * We treat VOID and CSTRING as legitimate scalar datatypes,
858 			 * mostly for the convenience of the JDBC driver (which wants to
859 			 * be able to do "SELECT * FROM foo()" for all legitimately
860 			 * user-callable functions).
861 			 */
862 			if (typid == VOIDOID || typid == CSTRINGOID)
863 				return TYPEFUNC_SCALAR;
864 			return TYPEFUNC_OTHER;
865 	}
866 	/* shouldn't get here, probably */
867 	return TYPEFUNC_OTHER;
868 }
869 
870 
871 /*
872  * get_func_arg_info
873  *
874  * Fetch info about the argument types, names, and IN/OUT modes from the
875  * pg_proc tuple.  Return value is the total number of arguments.
876  * Other results are palloc'd.  *p_argtypes is always filled in, but
877  * *p_argnames and *p_argmodes will be set NULL in the default cases
878  * (no names, and all IN arguments, respectively).
879  *
880  * Note that this function simply fetches what is in the pg_proc tuple;
881  * it doesn't do any interpretation of polymorphic types.
882  */
883 int
get_func_arg_info(HeapTuple procTup,Oid ** p_argtypes,char *** p_argnames,char ** p_argmodes)884 get_func_arg_info(HeapTuple procTup,
885 				  Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
886 {
887 	Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
888 	Datum		proallargtypes;
889 	Datum		proargmodes;
890 	Datum		proargnames;
891 	bool		isNull;
892 	ArrayType  *arr;
893 	int			numargs;
894 	Datum	   *elems;
895 	int			nelems;
896 	int			i;
897 
898 	/* First discover the total number of parameters and get their types */
899 	proallargtypes = SysCacheGetAttr(PROCOID, procTup,
900 									 Anum_pg_proc_proallargtypes,
901 									 &isNull);
902 	if (!isNull)
903 	{
904 		/*
905 		 * We expect the arrays to be 1-D arrays of the right types; verify
906 		 * that.  For the OID and char arrays, we don't need to use
907 		 * deconstruct_array() since the array data is just going to look like
908 		 * a C array of values.
909 		 */
910 		arr = DatumGetArrayTypeP(proallargtypes);	/* ensure not toasted */
911 		numargs = ARR_DIMS(arr)[0];
912 		if (ARR_NDIM(arr) != 1 ||
913 			numargs < 0 ||
914 			ARR_HASNULL(arr) ||
915 			ARR_ELEMTYPE(arr) != OIDOID)
916 			elog(ERROR, "proallargtypes is not a 1-D Oid array");
917 		Assert(numargs >= procStruct->pronargs);
918 		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
919 		memcpy(*p_argtypes, ARR_DATA_PTR(arr),
920 			   numargs * sizeof(Oid));
921 	}
922 	else
923 	{
924 		/* If no proallargtypes, use proargtypes */
925 		numargs = procStruct->proargtypes.dim1;
926 		Assert(numargs == procStruct->pronargs);
927 		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
928 		memcpy(*p_argtypes, procStruct->proargtypes.values,
929 			   numargs * sizeof(Oid));
930 	}
931 
932 	/* Get argument names, if available */
933 	proargnames = SysCacheGetAttr(PROCOID, procTup,
934 								  Anum_pg_proc_proargnames,
935 								  &isNull);
936 	if (isNull)
937 		*p_argnames = NULL;
938 	else
939 	{
940 		deconstruct_array(DatumGetArrayTypeP(proargnames),
941 						  TEXTOID, -1, false, 'i',
942 						  &elems, NULL, &nelems);
943 		if (nelems != numargs)	/* should not happen */
944 			elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
945 		*p_argnames = (char **) palloc(sizeof(char *) * numargs);
946 		for (i = 0; i < numargs; i++)
947 			(*p_argnames)[i] = TextDatumGetCString(elems[i]);
948 	}
949 
950 	/* Get argument modes, if available */
951 	proargmodes = SysCacheGetAttr(PROCOID, procTup,
952 								  Anum_pg_proc_proargmodes,
953 								  &isNull);
954 	if (isNull)
955 		*p_argmodes = NULL;
956 	else
957 	{
958 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
959 		if (ARR_NDIM(arr) != 1 ||
960 			ARR_DIMS(arr)[0] != numargs ||
961 			ARR_HASNULL(arr) ||
962 			ARR_ELEMTYPE(arr) != CHAROID)
963 			elog(ERROR, "proargmodes is not a 1-D char array");
964 		*p_argmodes = (char *) palloc(numargs * sizeof(char));
965 		memcpy(*p_argmodes, ARR_DATA_PTR(arr),
966 			   numargs * sizeof(char));
967 	}
968 
969 	return numargs;
970 }
971 
972 /*
973  * get_func_trftypes
974  *
975  * Returns the number of transformed types used by the function.
976  * If there are any, a palloc'd array of the type OIDs is returned
977  * into *p_trftypes.
978  */
979 int
get_func_trftypes(HeapTuple procTup,Oid ** p_trftypes)980 get_func_trftypes(HeapTuple procTup,
981 				  Oid **p_trftypes)
982 {
983 	Datum		protrftypes;
984 	ArrayType  *arr;
985 	int			nelems;
986 	bool		isNull;
987 
988 	protrftypes = SysCacheGetAttr(PROCOID, procTup,
989 								  Anum_pg_proc_protrftypes,
990 								  &isNull);
991 	if (!isNull)
992 	{
993 		/*
994 		 * We expect the arrays to be 1-D arrays of the right types; verify
995 		 * that.  For the OID and char arrays, we don't need to use
996 		 * deconstruct_array() since the array data is just going to look like
997 		 * a C array of values.
998 		 */
999 		arr = DatumGetArrayTypeP(protrftypes);	/* ensure not toasted */
1000 		nelems = ARR_DIMS(arr)[0];
1001 		if (ARR_NDIM(arr) != 1 ||
1002 			nelems < 0 ||
1003 			ARR_HASNULL(arr) ||
1004 			ARR_ELEMTYPE(arr) != OIDOID)
1005 			elog(ERROR, "protrftypes is not a 1-D Oid array");
1006 		*p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
1007 		memcpy(*p_trftypes, ARR_DATA_PTR(arr),
1008 			   nelems * sizeof(Oid));
1009 
1010 		return nelems;
1011 	}
1012 	else
1013 		return 0;
1014 }
1015 
1016 /*
1017  * get_func_input_arg_names
1018  *
1019  * Extract the names of input arguments only, given a function's
1020  * proargnames and proargmodes entries in Datum form.
1021  *
1022  * Returns the number of input arguments, which is the length of the
1023  * palloc'd array returned to *arg_names.  Entries for unnamed args
1024  * are set to NULL.  You don't get anything if proargnames is NULL.
1025  */
1026 int
get_func_input_arg_names(Datum proargnames,Datum proargmodes,char *** arg_names)1027 get_func_input_arg_names(Datum proargnames, Datum proargmodes,
1028 						 char ***arg_names)
1029 {
1030 	ArrayType  *arr;
1031 	int			numargs;
1032 	Datum	   *argnames;
1033 	char	   *argmodes;
1034 	char	  **inargnames;
1035 	int			numinargs;
1036 	int			i;
1037 
1038 	/* Do nothing if null proargnames */
1039 	if (proargnames == PointerGetDatum(NULL))
1040 	{
1041 		*arg_names = NULL;
1042 		return 0;
1043 	}
1044 
1045 	/*
1046 	 * We expect the arrays to be 1-D arrays of the right types; verify that.
1047 	 * For proargmodes, we don't need to use deconstruct_array() since the
1048 	 * array data is just going to look like a C array of values.
1049 	 */
1050 	arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1051 	if (ARR_NDIM(arr) != 1 ||
1052 		ARR_HASNULL(arr) ||
1053 		ARR_ELEMTYPE(arr) != TEXTOID)
1054 		elog(ERROR, "proargnames is not a 1-D text array");
1055 	deconstruct_array(arr, TEXTOID, -1, false, 'i',
1056 					  &argnames, NULL, &numargs);
1057 	if (proargmodes != PointerGetDatum(NULL))
1058 	{
1059 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1060 		if (ARR_NDIM(arr) != 1 ||
1061 			ARR_DIMS(arr)[0] != numargs ||
1062 			ARR_HASNULL(arr) ||
1063 			ARR_ELEMTYPE(arr) != CHAROID)
1064 			elog(ERROR, "proargmodes is not a 1-D char array");
1065 		argmodes = (char *) ARR_DATA_PTR(arr);
1066 	}
1067 	else
1068 		argmodes = NULL;
1069 
1070 	/* zero elements probably shouldn't happen, but handle it gracefully */
1071 	if (numargs <= 0)
1072 	{
1073 		*arg_names = NULL;
1074 		return 0;
1075 	}
1076 
1077 	/* extract input-argument names */
1078 	inargnames = (char **) palloc(numargs * sizeof(char *));
1079 	numinargs = 0;
1080 	for (i = 0; i < numargs; i++)
1081 	{
1082 		if (argmodes == NULL ||
1083 			argmodes[i] == PROARGMODE_IN ||
1084 			argmodes[i] == PROARGMODE_INOUT ||
1085 			argmodes[i] == PROARGMODE_VARIADIC)
1086 		{
1087 			char	   *pname = TextDatumGetCString(argnames[i]);
1088 
1089 			if (pname[0] != '\0')
1090 				inargnames[numinargs] = pname;
1091 			else
1092 				inargnames[numinargs] = NULL;
1093 			numinargs++;
1094 		}
1095 	}
1096 
1097 	*arg_names = inargnames;
1098 	return numinargs;
1099 }
1100 
1101 
1102 /*
1103  * get_func_result_name
1104  *
1105  * If the function has exactly one output parameter, and that parameter
1106  * is named, return the name (as a palloc'd string).  Else return NULL.
1107  *
1108  * This is used to determine the default output column name for functions
1109  * returning scalar types.
1110  */
1111 char *
get_func_result_name(Oid functionId)1112 get_func_result_name(Oid functionId)
1113 {
1114 	char	   *result;
1115 	HeapTuple	procTuple;
1116 	Datum		proargmodes;
1117 	Datum		proargnames;
1118 	bool		isnull;
1119 	ArrayType  *arr;
1120 	int			numargs;
1121 	char	   *argmodes;
1122 	Datum	   *argnames;
1123 	int			numoutargs;
1124 	int			nargnames;
1125 	int			i;
1126 
1127 	/* First fetch the function's pg_proc row */
1128 	procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
1129 	if (!HeapTupleIsValid(procTuple))
1130 		elog(ERROR, "cache lookup failed for function %u", functionId);
1131 
1132 	/* If there are no named OUT parameters, return NULL */
1133 	if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL) ||
1134 		heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
1135 		result = NULL;
1136 	else
1137 	{
1138 		/* Get the data out of the tuple */
1139 		proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1140 									  Anum_pg_proc_proargmodes,
1141 									  &isnull);
1142 		Assert(!isnull);
1143 		proargnames = SysCacheGetAttr(PROCOID, procTuple,
1144 									  Anum_pg_proc_proargnames,
1145 									  &isnull);
1146 		Assert(!isnull);
1147 
1148 		/*
1149 		 * We expect the arrays to be 1-D arrays of the right types; verify
1150 		 * that.  For the char array, we don't need to use deconstruct_array()
1151 		 * since the array data is just going to look like a C array of
1152 		 * values.
1153 		 */
1154 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1155 		numargs = ARR_DIMS(arr)[0];
1156 		if (ARR_NDIM(arr) != 1 ||
1157 			numargs < 0 ||
1158 			ARR_HASNULL(arr) ||
1159 			ARR_ELEMTYPE(arr) != CHAROID)
1160 			elog(ERROR, "proargmodes is not a 1-D char array");
1161 		argmodes = (char *) ARR_DATA_PTR(arr);
1162 		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1163 		if (ARR_NDIM(arr) != 1 ||
1164 			ARR_DIMS(arr)[0] != numargs ||
1165 			ARR_HASNULL(arr) ||
1166 			ARR_ELEMTYPE(arr) != TEXTOID)
1167 			elog(ERROR, "proargnames is not a 1-D text array");
1168 		deconstruct_array(arr, TEXTOID, -1, false, 'i',
1169 						  &argnames, NULL, &nargnames);
1170 		Assert(nargnames == numargs);
1171 
1172 		/* scan for output argument(s) */
1173 		result = NULL;
1174 		numoutargs = 0;
1175 		for (i = 0; i < numargs; i++)
1176 		{
1177 			if (argmodes[i] == PROARGMODE_IN ||
1178 				argmodes[i] == PROARGMODE_VARIADIC)
1179 				continue;
1180 			Assert(argmodes[i] == PROARGMODE_OUT ||
1181 				   argmodes[i] == PROARGMODE_INOUT ||
1182 				   argmodes[i] == PROARGMODE_TABLE);
1183 			if (++numoutargs > 1)
1184 			{
1185 				/* multiple out args, so forget it */
1186 				result = NULL;
1187 				break;
1188 			}
1189 			result = TextDatumGetCString(argnames[i]);
1190 			if (result == NULL || result[0] == '\0')
1191 			{
1192 				/* Parameter is not named, so forget it */
1193 				result = NULL;
1194 				break;
1195 			}
1196 		}
1197 	}
1198 
1199 	ReleaseSysCache(procTuple);
1200 
1201 	return result;
1202 }
1203 
1204 
1205 /*
1206  * build_function_result_tupdesc_t
1207  *
1208  * Given a pg_proc row for a function, return a tuple descriptor for the
1209  * result rowtype, or NULL if the function does not have OUT parameters.
1210  *
1211  * Note that this does not handle resolution of polymorphic types;
1212  * that is deliberate.
1213  */
1214 TupleDesc
build_function_result_tupdesc_t(HeapTuple procTuple)1215 build_function_result_tupdesc_t(HeapTuple procTuple)
1216 {
1217 	Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1218 	Datum		proallargtypes;
1219 	Datum		proargmodes;
1220 	Datum		proargnames;
1221 	bool		isnull;
1222 
1223 	/* Return NULL if the function isn't declared to return RECORD */
1224 	if (procform->prorettype != RECORDOID)
1225 		return NULL;
1226 
1227 	/* If there are no OUT parameters, return NULL */
1228 	if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
1229 		heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
1230 		return NULL;
1231 
1232 	/* Get the data out of the tuple */
1233 	proallargtypes = SysCacheGetAttr(PROCOID, procTuple,
1234 									 Anum_pg_proc_proallargtypes,
1235 									 &isnull);
1236 	Assert(!isnull);
1237 	proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1238 								  Anum_pg_proc_proargmodes,
1239 								  &isnull);
1240 	Assert(!isnull);
1241 	proargnames = SysCacheGetAttr(PROCOID, procTuple,
1242 								  Anum_pg_proc_proargnames,
1243 								  &isnull);
1244 	if (isnull)
1245 		proargnames = PointerGetDatum(NULL);	/* just to be sure */
1246 
1247 	return build_function_result_tupdesc_d(procform->prokind,
1248 										   proallargtypes,
1249 										   proargmodes,
1250 										   proargnames);
1251 }
1252 
1253 /*
1254  * build_function_result_tupdesc_d
1255  *
1256  * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
1257  * proargmodes, and proargnames arrays.  This is split out for the
1258  * convenience of ProcedureCreate, which needs to be able to compute the
1259  * tupledesc before actually creating the function.
1260  *
1261  * For functions (but not for procedures), returns NULL if there are not at
1262  * least two OUT or INOUT arguments.
1263  */
1264 TupleDesc
build_function_result_tupdesc_d(char prokind,Datum proallargtypes,Datum proargmodes,Datum proargnames)1265 build_function_result_tupdesc_d(char prokind,
1266 								Datum proallargtypes,
1267 								Datum proargmodes,
1268 								Datum proargnames)
1269 {
1270 	TupleDesc	desc;
1271 	ArrayType  *arr;
1272 	int			numargs;
1273 	Oid		   *argtypes;
1274 	char	   *argmodes;
1275 	Datum	   *argnames = NULL;
1276 	Oid		   *outargtypes;
1277 	char	  **outargnames;
1278 	int			numoutargs;
1279 	int			nargnames;
1280 	int			i;
1281 
1282 	/* Can't have output args if columns are null */
1283 	if (proallargtypes == PointerGetDatum(NULL) ||
1284 		proargmodes == PointerGetDatum(NULL))
1285 		return NULL;
1286 
1287 	/*
1288 	 * We expect the arrays to be 1-D arrays of the right types; verify that.
1289 	 * For the OID and char arrays, we don't need to use deconstruct_array()
1290 	 * since the array data is just going to look like a C array of values.
1291 	 */
1292 	arr = DatumGetArrayTypeP(proallargtypes);	/* ensure not toasted */
1293 	numargs = ARR_DIMS(arr)[0];
1294 	if (ARR_NDIM(arr) != 1 ||
1295 		numargs < 0 ||
1296 		ARR_HASNULL(arr) ||
1297 		ARR_ELEMTYPE(arr) != OIDOID)
1298 		elog(ERROR, "proallargtypes is not a 1-D Oid array");
1299 	argtypes = (Oid *) ARR_DATA_PTR(arr);
1300 	arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
1301 	if (ARR_NDIM(arr) != 1 ||
1302 		ARR_DIMS(arr)[0] != numargs ||
1303 		ARR_HASNULL(arr) ||
1304 		ARR_ELEMTYPE(arr) != CHAROID)
1305 		elog(ERROR, "proargmodes is not a 1-D char array");
1306 	argmodes = (char *) ARR_DATA_PTR(arr);
1307 	if (proargnames != PointerGetDatum(NULL))
1308 	{
1309 		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
1310 		if (ARR_NDIM(arr) != 1 ||
1311 			ARR_DIMS(arr)[0] != numargs ||
1312 			ARR_HASNULL(arr) ||
1313 			ARR_ELEMTYPE(arr) != TEXTOID)
1314 			elog(ERROR, "proargnames is not a 1-D text array");
1315 		deconstruct_array(arr, TEXTOID, -1, false, 'i',
1316 						  &argnames, NULL, &nargnames);
1317 		Assert(nargnames == numargs);
1318 	}
1319 
1320 	/* zero elements probably shouldn't happen, but handle it gracefully */
1321 	if (numargs <= 0)
1322 		return NULL;
1323 
1324 	/* extract output-argument types and names */
1325 	outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1326 	outargnames = (char **) palloc(numargs * sizeof(char *));
1327 	numoutargs = 0;
1328 	for (i = 0; i < numargs; i++)
1329 	{
1330 		char	   *pname;
1331 
1332 		if (argmodes[i] == PROARGMODE_IN ||
1333 			argmodes[i] == PROARGMODE_VARIADIC)
1334 			continue;
1335 		Assert(argmodes[i] == PROARGMODE_OUT ||
1336 			   argmodes[i] == PROARGMODE_INOUT ||
1337 			   argmodes[i] == PROARGMODE_TABLE);
1338 		outargtypes[numoutargs] = argtypes[i];
1339 		if (argnames)
1340 			pname = TextDatumGetCString(argnames[i]);
1341 		else
1342 			pname = NULL;
1343 		if (pname == NULL || pname[0] == '\0')
1344 		{
1345 			/* Parameter is not named, so gin up a column name */
1346 			pname = psprintf("column%d", numoutargs + 1);
1347 		}
1348 		outargnames[numoutargs] = pname;
1349 		numoutargs++;
1350 	}
1351 
1352 	/*
1353 	 * If there is no output argument, or only one, the function does not
1354 	 * return tuples.
1355 	 */
1356 	if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1357 		return NULL;
1358 
1359 	desc = CreateTemplateTupleDesc(numoutargs);
1360 	for (i = 0; i < numoutargs; i++)
1361 	{
1362 		TupleDescInitEntry(desc, i + 1,
1363 						   outargnames[i],
1364 						   outargtypes[i],
1365 						   -1,
1366 						   0);
1367 	}
1368 
1369 	return desc;
1370 }
1371 
1372 
1373 /*
1374  * RelationNameGetTupleDesc
1375  *
1376  * Given a (possibly qualified) relation name, build a TupleDesc.
1377  *
1378  * Note: while this works as advertised, it's seldom the best way to
1379  * build a tupdesc for a function's result type.  It's kept around
1380  * only for backwards compatibility with existing user-written code.
1381  */
1382 TupleDesc
RelationNameGetTupleDesc(const char * relname)1383 RelationNameGetTupleDesc(const char *relname)
1384 {
1385 	RangeVar   *relvar;
1386 	Relation	rel;
1387 	TupleDesc	tupdesc;
1388 	List	   *relname_list;
1389 
1390 	/* Open relation and copy the tuple description */
1391 	relname_list = stringToQualifiedNameList(relname);
1392 	relvar = makeRangeVarFromNameList(relname_list);
1393 	rel = relation_openrv(relvar, AccessShareLock);
1394 	tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1395 	relation_close(rel, AccessShareLock);
1396 
1397 	return tupdesc;
1398 }
1399 
1400 /*
1401  * TypeGetTupleDesc
1402  *
1403  * Given a type Oid, build a TupleDesc.  (In most cases you should be
1404  * using get_call_result_type or one of its siblings instead of this
1405  * routine, so that you can handle OUT parameters, RECORD result type,
1406  * and polymorphic results.)
1407  *
1408  * If the type is composite, *and* a colaliases List is provided, *and*
1409  * the List is of natts length, use the aliases instead of the relation
1410  * attnames.  (NB: this usage is deprecated since it may result in
1411  * creation of unnecessary transient record types.)
1412  *
1413  * If the type is a base type, a single item alias List is required.
1414  */
1415 TupleDesc
TypeGetTupleDesc(Oid typeoid,List * colaliases)1416 TypeGetTupleDesc(Oid typeoid, List *colaliases)
1417 {
1418 	Oid			base_typeoid;
1419 	TypeFuncClass functypclass = get_type_func_class(typeoid, &base_typeoid);
1420 	TupleDesc	tupdesc = NULL;
1421 
1422 	/*
1423 	 * Build a suitable tupledesc representing the output rows.  We
1424 	 * intentionally do not support TYPEFUNC_COMPOSITE_DOMAIN here, as it's
1425 	 * unlikely that legacy callers of this obsolete function would be
1426 	 * prepared to apply domain constraints.
1427 	 */
1428 	if (functypclass == TYPEFUNC_COMPOSITE)
1429 	{
1430 		/* Composite data type, e.g. a table's row type */
1431 		tupdesc = lookup_rowtype_tupdesc_copy(base_typeoid, -1);
1432 
1433 		if (colaliases != NIL)
1434 		{
1435 			int			natts = tupdesc->natts;
1436 			int			varattno;
1437 
1438 			/* does the list length match the number of attributes? */
1439 			if (list_length(colaliases) != natts)
1440 				ereport(ERROR,
1441 						(errcode(ERRCODE_DATATYPE_MISMATCH),
1442 						 errmsg("number of aliases does not match number of columns")));
1443 
1444 			/* OK, use the aliases instead */
1445 			for (varattno = 0; varattno < natts; varattno++)
1446 			{
1447 				char	   *label = strVal(list_nth(colaliases, varattno));
1448 				Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1449 
1450 				if (label != NULL)
1451 					namestrcpy(&(attr->attname), label);
1452 			}
1453 
1454 			/* The tuple type is now an anonymous record type */
1455 			tupdesc->tdtypeid = RECORDOID;
1456 			tupdesc->tdtypmod = -1;
1457 		}
1458 	}
1459 	else if (functypclass == TYPEFUNC_SCALAR)
1460 	{
1461 		/* Base data type, i.e. scalar */
1462 		char	   *attname;
1463 
1464 		/* the alias list is required for base types */
1465 		if (colaliases == NIL)
1466 			ereport(ERROR,
1467 					(errcode(ERRCODE_DATATYPE_MISMATCH),
1468 					 errmsg("no column alias was provided")));
1469 
1470 		/* the alias list length must be 1 */
1471 		if (list_length(colaliases) != 1)
1472 			ereport(ERROR,
1473 					(errcode(ERRCODE_DATATYPE_MISMATCH),
1474 					 errmsg("number of aliases does not match number of columns")));
1475 
1476 		/* OK, get the column alias */
1477 		attname = strVal(linitial(colaliases));
1478 
1479 		tupdesc = CreateTemplateTupleDesc(1);
1480 		TupleDescInitEntry(tupdesc,
1481 						   (AttrNumber) 1,
1482 						   attname,
1483 						   typeoid,
1484 						   -1,
1485 						   0);
1486 	}
1487 	else if (functypclass == TYPEFUNC_RECORD)
1488 	{
1489 		/* XXX can't support this because typmod wasn't passed in ... */
1490 		ereport(ERROR,
1491 				(errcode(ERRCODE_DATATYPE_MISMATCH),
1492 				 errmsg("could not determine row description for function returning record")));
1493 	}
1494 	else
1495 	{
1496 		/* crummy error message, but parser should have caught this */
1497 		elog(ERROR, "function in FROM has unsupported return type");
1498 	}
1499 
1500 	return tupdesc;
1501 }
1502 
1503 /*
1504  * extract_variadic_args
1505  *
1506  * Extract a set of argument values, types and NULL markers for a given
1507  * input function which makes use of a VARIADIC input whose argument list
1508  * depends on the caller context. When doing a VARIADIC call, the caller
1509  * has provided one argument made of an array of values, so deconstruct the
1510  * array data before using it for the next processing. If no VARIADIC call
1511  * is used, just fill in the status data based on all the arguments given
1512  * by the caller.
1513  *
1514  * This function returns the number of arguments generated, or -1 in the
1515  * case of "VARIADIC NULL".
1516  */
1517 int
extract_variadic_args(FunctionCallInfo fcinfo,int variadic_start,bool convert_unknown,Datum ** args,Oid ** types,bool ** nulls)1518 extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
1519 					  bool convert_unknown, Datum **args, Oid **types,
1520 					  bool **nulls)
1521 {
1522 	bool		variadic = get_fn_expr_variadic(fcinfo->flinfo);
1523 	Datum	   *args_res;
1524 	bool	   *nulls_res;
1525 	Oid		   *types_res;
1526 	int			nargs,
1527 				i;
1528 
1529 	*args = NULL;
1530 	*types = NULL;
1531 	*nulls = NULL;
1532 
1533 	if (variadic)
1534 	{
1535 		ArrayType  *array_in;
1536 		Oid			element_type;
1537 		bool		typbyval;
1538 		char		typalign;
1539 		int16		typlen;
1540 
1541 		Assert(PG_NARGS() == variadic_start + 1);
1542 
1543 		if (PG_ARGISNULL(variadic_start))
1544 			return -1;
1545 
1546 		array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
1547 		element_type = ARR_ELEMTYPE(array_in);
1548 
1549 		get_typlenbyvalalign(element_type,
1550 							 &typlen, &typbyval, &typalign);
1551 		deconstruct_array(array_in, element_type, typlen, typbyval,
1552 						  typalign, &args_res, &nulls_res,
1553 						  &nargs);
1554 
1555 		/* All the elements of the array have the same type */
1556 		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1557 		for (i = 0; i < nargs; i++)
1558 			types_res[i] = element_type;
1559 	}
1560 	else
1561 	{
1562 		nargs = PG_NARGS() - variadic_start;
1563 		Assert(nargs > 0);
1564 		nulls_res = (bool *) palloc0(nargs * sizeof(bool));
1565 		args_res = (Datum *) palloc0(nargs * sizeof(Datum));
1566 		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1567 
1568 		for (i = 0; i < nargs; i++)
1569 		{
1570 			nulls_res[i] = PG_ARGISNULL(i + variadic_start);
1571 			types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
1572 											   i + variadic_start);
1573 
1574 			/*
1575 			 * Turn a constant (more or less literal) value that's of unknown
1576 			 * type into text if required. Unknowns come in as a cstring
1577 			 * pointer. Note: for functions declared as taking type "any", the
1578 			 * parser will not do any type conversion on unknown-type literals
1579 			 * (that is, undecorated strings or NULLs).
1580 			 */
1581 			if (convert_unknown &&
1582 				types_res[i] == UNKNOWNOID &&
1583 				get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
1584 			{
1585 				types_res[i] = TEXTOID;
1586 
1587 				if (PG_ARGISNULL(i + variadic_start))
1588 					args_res[i] = (Datum) 0;
1589 				else
1590 					args_res[i] =
1591 						CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
1592 			}
1593 			else
1594 			{
1595 				/* no conversion needed, just take the datum as given */
1596 				args_res[i] = PG_GETARG_DATUM(i + variadic_start);
1597 			}
1598 
1599 			if (!OidIsValid(types_res[i]) ||
1600 				(convert_unknown && types_res[i] == UNKNOWNOID))
1601 				ereport(ERROR,
1602 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1603 						 errmsg("could not determine data type for argument %d",
1604 								i + 1)));
1605 		}
1606 	}
1607 
1608 	/* Fill in results */
1609 	*args = args_res;
1610 	*nulls = nulls_res;
1611 	*types = types_res;
1612 
1613 	return nargs;
1614 }
1615