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