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