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