PostgreSQL Source Code  git master
plpy_typeio.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_typeio.h"
#include "plpython.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for plpy_typeio.c:

Go to the source code of this file.

Functions

static PyObject * PLyBool_FromBool (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyFloat_FromFloat4 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyFloat_FromFloat8 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyDecimal_FromNumeric (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyInt_FromInt16 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyInt_FromInt32 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyLong_FromInt64 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyLong_FromOid (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyBytes_FromBytea (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyString_FromScalar (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyObject_FromTransform (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyList_FromArray (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyList_FromArray_recurse (PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
 
static PyObject * PLyDict_FromComposite (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyDict_FromTuple (PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
 
static Datum PLyObject_ToBool (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToBytea (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToComposite (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToScalar (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToDomain (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToTransform (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLySequence_ToArray (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static void PLySequence_ToArray_recurse (PLyObToDatum *elm, PyObject *list, int *dims, int ndim, int dim, Datum *elems, bool *nulls, int *currelem)
 
static Datum PLyString_ToComposite (PLyObToDatum *arg, PyObject *string, bool inarray)
 
static Datum PLyMapping_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
 
static Datum PLySequence_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
 
static Datum PLyGenericObject_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
 
PyObject * PLy_input_convert (PLyDatumToOb *arg, Datum val)
 
Datum PLy_output_convert (PLyObToDatum *arg, PyObject *val, bool *isnull)
 
PyObject * PLy_input_from_tuple (PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
 
void PLy_input_setup_tuple (PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_tuple (PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_record (PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_func (PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
 
void PLy_input_setup_func (PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
 
char * PLyObject_AsString (PyObject *plrv)
 

Function Documentation

◆ PLy_input_convert()

PyObject* PLy_input_convert ( PLyDatumToOb arg,
Datum  val 
)

Definition at line 80 of file plpy_typeio.c.

References PLyDatumToOb::func, MemoryContextReset(), MemoryContextSwitchTo(), PLy_current_execution_context(), and PLy_get_scratch_context().

Referenced by PLy_function_build_args().

81 {
82  PyObject *result;
84  MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
85  MemoryContext oldcontext;
86 
87  /*
88  * Do the work in the scratch context to avoid leaking memory from the
89  * datatype output function calls. (The individual PLyDatumToObFunc
90  * functions can't reset the scratch context, because they recurse and an
91  * inner one might clobber data an outer one still needs. So we do it
92  * once at the outermost recursion level.)
93  *
94  * We reset the scratch context before, not after, each conversion cycle.
95  * This way we aren't on the hook to release a Python refcount on the
96  * result object in case MemoryContextReset throws an error.
97  */
98  MemoryContextReset(scratch_context);
99 
100  oldcontext = MemoryContextSwitchTo(scratch_context);
101 
102  result = arg->func(arg, val);
103 
104  MemoryContextSwitchTo(oldcontext);
105 
106  return result;
107 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
long val
Definition: informix.c:664
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:419

◆ PLy_input_from_tuple()

PyObject* PLy_input_from_tuple ( PLyDatumToOb arg,
HeapTuple  tuple,
TupleDesc  desc,
bool  include_generated 
)

Definition at line 133 of file plpy_typeio.c.

References MemoryContextReset(), MemoryContextSwitchTo(), PLy_current_execution_context(), PLy_get_scratch_context(), and PLyDict_FromTuple().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_spi_execute_fetch_result(), and PLy_trigger_build_args().

134 {
135  PyObject *dict;
137  MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
138  MemoryContext oldcontext;
139 
140  /*
141  * As in PLy_input_convert, do the work in the scratch context.
142  */
143  MemoryContextReset(scratch_context);
144 
145  oldcontext = MemoryContextSwitchTo(scratch_context);
146 
147  dict = PLyDict_FromTuple(arg, tuple, desc, include_generated);
148 
149  MemoryContextSwitchTo(oldcontext);
150 
151  return dict;
152 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:814
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:419

◆ PLy_input_setup_func()

void PLy_input_setup_func ( PLyDatumToOb arg,
MemoryContext  arg_mcxt,
Oid  typeOid,
int32  typmod,
PLyProcedure proc 
)

Definition at line 417 of file plpy_typeio.c.

References PLyDatumToOb::array, PLyTupleToOb::atts, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, PLyArrayToOb::elm, fmgr_info_cxt(), PLyDatumToOb::func, get_transform_fromsql(), getTypeOutputInfo(), INVALID_TUPLEDESC_IDENTIFIER, PLyProcedure::langid, lookup_type_cache(), PLyDatumToOb::mcxt, MemoryContextAllocZero(), PLyTupleToOb::natts, OidIsValid, PLy_input_setup_func(), PLyBool_FromBool(), PLyBytes_FromBytea(), PLyDecimal_FromNumeric(), PLyDict_FromComposite(), PLyFloat_FromFloat4(), PLyFloat_FromFloat8(), PLyInt_FromInt16(), PLyInt_FromInt32(), PLyList_FromArray(), PLyLong_FromInt64(), PLyLong_FromOid(), PLyObject_FromTransform(), PLyString_FromScalar(), PLyTupleToOb::recdesc, PLyDatumToOb::scalar, PLyDatumToOb::transform, PLyProcedure::trftypes, PLyTupleToOb::tupdescid, PLyDatumToOb::tuple, TypeCacheEntry::typalign, PLyDatumToOb::typalign, TypeCacheEntry::typbyval, PLyDatumToOb::typbyval, TYPECACHE_DOMAIN_BASE_INFO, TypeCacheEntry::typelem, PLyTupleToOb::typentry, PLyScalarToOb::typfunc, TypeCacheEntry::typlen, PLyDatumToOb::typlen, PLyDatumToOb::typmod, PLyDatumToOb::typoid, PLyTransformToOb::typtransform, TypeCacheEntry::typtype, and PLyDatumToOb::u.

Referenced by PLy_cursor_plan(), PLy_cursor_query(), PLy_exec_trigger(), PLy_input_setup_func(), PLy_input_setup_tuple(), PLy_procedure_create(), and PLy_spi_execute_fetch_result().

420 {
421  TypeCacheEntry *typentry;
422  char typtype;
423  Oid trfuncid;
424  Oid typoutput;
425  bool typisvarlena;
426 
427  /* Since this is recursive, it could theoretically be driven to overflow */
429 
430  arg->typoid = typeOid;
431  arg->typmod = typmod;
432  arg->mcxt = arg_mcxt;
433 
434  /*
435  * Fetch typcache entry for the target type, asking for whatever info
436  * we'll need later. RECORD is a special case: just treat it as composite
437  * without bothering with the typcache entry.
438  */
439  if (typeOid != RECORDOID)
440  {
441  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
442  typtype = typentry->typtype;
443  arg->typbyval = typentry->typbyval;
444  arg->typlen = typentry->typlen;
445  arg->typalign = typentry->typalign;
446  }
447  else
448  {
449  typentry = NULL;
450  typtype = TYPTYPE_COMPOSITE;
451  /* hard-wired knowledge about type RECORD: */
452  arg->typbyval = false;
453  arg->typlen = -1;
454  arg->typalign = 'd';
455  }
456 
457  /*
458  * Choose conversion method. Note that transform functions are checked
459  * for composite and scalar types, but not for arrays or domains. This is
460  * somewhat historical, but we'd have a problem allowing them on domains,
461  * since we drill down through all levels of a domain nest without looking
462  * at the intermediate levels at all.
463  */
464  if (typtype == TYPTYPE_DOMAIN)
465  {
466  /* Domain --- we don't care, just recurse down to the base type */
467  PLy_input_setup_func(arg, arg_mcxt,
468  typentry->domainBaseType,
469  typentry->domainBaseTypmod,
470  proc);
471  }
472  else if (typentry &&
473  OidIsValid(typentry->typelem) && typentry->typlen == -1)
474  {
475  /* Standard varlena array (cf. get_element_type) */
476  arg->func = PLyList_FromArray;
477  /* Recursively set up conversion info for the element type */
478  arg->u.array.elm = (PLyDatumToOb *)
479  MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb));
480  PLy_input_setup_func(arg->u.array.elm, arg_mcxt,
481  typentry->typelem, typmod,
482  proc);
483  }
484  else if ((trfuncid = get_transform_fromsql(typeOid,
485  proc->langid,
486  proc->trftypes)))
487  {
489  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
490  }
491  else if (typtype == TYPTYPE_COMPOSITE)
492  {
493  /* Named composite type, or RECORD */
495  /* We'll set up the per-field data later */
496  arg->u.tuple.recdesc = NULL;
497  arg->u.tuple.typentry = typentry;
499  arg->u.tuple.atts = NULL;
500  arg->u.tuple.natts = 0;
501  }
502  else
503  {
504  /* Scalar type, but we have a couple of special cases */
505  switch (typeOid)
506  {
507  case BOOLOID:
508  arg->func = PLyBool_FromBool;
509  break;
510  case FLOAT4OID:
511  arg->func = PLyFloat_FromFloat4;
512  break;
513  case FLOAT8OID:
514  arg->func = PLyFloat_FromFloat8;
515  break;
516  case NUMERICOID:
518  break;
519  case INT2OID:
520  arg->func = PLyInt_FromInt16;
521  break;
522  case INT4OID:
523  arg->func = PLyInt_FromInt32;
524  break;
525  case INT8OID:
526  arg->func = PLyLong_FromInt64;
527  break;
528  case OIDOID:
529  arg->func = PLyLong_FromOid;
530  break;
531  case BYTEAOID:
532  arg->func = PLyBytes_FromBytea;
533  break;
534  default:
535  arg->func = PLyString_FromScalar;
536  getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
537  fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
538  break;
539  }
540  }
541 }
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1900
static PyObject * PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:615
TupleDesc recdesc
Definition: plpy_typeio.h:43
static PyObject * PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:609
PLyDatumToOb * atts
Definition: plpy_typeio.h:48
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2674
FmgrInfo typfunc
Definition: plpy_typeio.h:32
static PyObject * PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:549
uint64 tupdescid
Definition: plpy_typeio.h:46
TypeCacheEntry * typentry
Definition: plpy_typeio.h:45
unsigned int Oid
Definition: postgres_ext.h:31
int16 typlen
Definition: typcache.h:37
#define OidIsValid(objectId)
Definition: c.h:645
bool typbyval
Definition: typcache.h:38
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:146
static PyObject * PLyString_FromScalar(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:641
FmgrInfo typtransform
Definition: plpy_typeio.h:54
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:780
Oid domainBaseType
Definition: typcache.h:105
static PyObject * PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:603
PLyArrayToOb array
Definition: plpy_typeio.h:69
static PyObject * PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:563
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
PLyTransformToOb transform
Definition: plpy_typeio.h:71
static PyObject * PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:557
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:627
void check_stack_depth(void)
Definition: postgres.c:3284
int32 typmod
Definition: plpy_typeio.h:61
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:417
int32 domainBaseTypmod
Definition: typcache.h:106
int16 typlen
Definition: plpy_typeio.h:63
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:134
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:569
PLyDatumToOb * elm
Definition: plpy_typeio.h:37
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:140
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:322
char typtype
Definition: typcache.h:41
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:666
static PyObject * PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:621
PLyScalarToOb scalar
Definition: plpy_typeio.h:68
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:654
char typalign
Definition: typcache.h:39
union PLyDatumToOb::@165 u
MemoryContext mcxt
Definition: plpy_typeio.h:65
PLyTupleToOb tuple
Definition: plpy_typeio.h:70

◆ PLy_input_setup_tuple()

void PLy_input_setup_tuple ( PLyDatumToOb arg,
TupleDesc  desc,
PLyProcedure proc 
)

Definition at line 164 of file plpy_typeio.c.

References Assert, PLyTupleToOb::atts, PLyDatumToOb::func, i, PLyDatumToOb::mcxt, MemoryContextAllocZero(), PLyTupleToOb::natts, TupleDescData::natts, pfree(), PLy_input_setup_func(), PLyDict_FromComposite(), PLyTupleToOb::recdesc, PLyDatumToOb::tuple, TupleDescAttr, PLyDatumToOb::typmod, PLyDatumToOb::typoid, and PLyDatumToOb::u.

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_exec_trigger(), PLy_spi_execute_fetch_result(), and PLyDict_FromComposite().

165 {
166  int i;
167 
168  /* We should be working on a previously-set-up struct */
170 
171  /* Save pointer to tupdesc, but only if this is an anonymous record type */
172  if (arg->typoid == RECORDOID && arg->typmod < 0)
173  arg->u.tuple.recdesc = desc;
174 
175  /* (Re)allocate atts array as needed */
176  if (arg->u.tuple.natts != desc->natts)
177  {
178  if (arg->u.tuple.atts)
179  pfree(arg->u.tuple.atts);
180  arg->u.tuple.natts = desc->natts;
181  arg->u.tuple.atts = (PLyDatumToOb *)
183  desc->natts * sizeof(PLyDatumToOb));
184  }
185 
186  /* Fill the atts entries, except for dropped columns */
187  for (i = 0; i < desc->natts; i++)
188  {
189  Form_pg_attribute attr = TupleDescAttr(desc, i);
190  PLyDatumToOb *att = &arg->u.tuple.atts[i];
191 
192  if (attr->attisdropped)
193  continue;
194 
195  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
196  continue; /* already set up this entry */
197 
198  PLy_input_setup_func(att, arg->mcxt,
199  attr->atttypid, attr->atttypmod,
200  proc);
201  }
202 }
TupleDesc recdesc
Definition: plpy_typeio.h:43
PLyDatumToOb * atts
Definition: plpy_typeio.h:48
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:780
void pfree(void *pointer)
Definition: mcxt.c:1056
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
int32 typmod
Definition: plpy_typeio.h:61
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:417
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define Assert(condition)
Definition: c.h:739
int i
union PLyDatumToOb::@165 u
MemoryContext mcxt
Definition: plpy_typeio.h:65
PLyTupleToOb tuple
Definition: plpy_typeio.h:70

◆ PLy_output_convert()

Datum PLy_output_convert ( PLyObToDatum arg,
PyObject *  val,
bool isnull 
)

Definition at line 119 of file plpy_typeio.c.

References PLyObToDatum::func.

Referenced by PLy_cursor_plan(), PLy_exec_function(), PLy_modify_tuple(), and PLy_spi_execute_plan().

120 {
121  /* at outer level, we are not considering an array element */
122  return arg->func(arg, val, isnull, false);
123 }
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
long val
Definition: informix.c:664

◆ PLy_output_setup_func()

void PLy_output_setup_func ( PLyObToDatum arg,
MemoryContext  arg_mcxt,
Oid  typeOid,
int32  typmod,
PLyProcedure proc 
)

Definition at line 295 of file plpy_typeio.c.

References PLyObToDatum::array, PLyObToTuple::atts, PLyObToDomain::base, check_stack_depth(), PLyObToDatum::domain, PLyObToDomain::domain_info, TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, PLyObToArray::elm, PLyObToArray::elmbasetype, fmgr_info_cxt(), FmgrInfo::fn_oid, PLyObToDatum::func, get_transform_tosql(), getBaseType(), getTypeInputInfo(), INVALID_TUPLEDESC_IDENTIFIER, InvalidOid, PLyProcedure::langid, lookup_type_cache(), PLyObToDatum::mcxt, MemoryContextAllocZero(), PLyObToTuple::natts, OidIsValid, PLy_output_setup_func(), PLyObject_ToBool(), PLyObject_ToBytea(), PLyObject_ToComposite(), PLyObject_ToDomain(), PLyObject_ToScalar(), PLyObject_ToTransform(), PLySequence_ToArray(), PLyObToTuple::recdesc, PLyObToTuple::recinfunc, PLyObToDatum::scalar, PLyObToDatum::transform, PLyProcedure::trftypes, PLyObToTuple::tupdescid, PLyObToDatum::tuple, TypeCacheEntry::typalign, PLyObToDatum::typalign, TypeCacheEntry::typbyval, PLyObToDatum::typbyval, TYPECACHE_DOMAIN_BASE_INFO, TypeCacheEntry::typelem, PLyObToTuple::typentry, PLyObToScalar::typfunc, PLyObToScalar::typioparam, TypeCacheEntry::typlen, PLyObToDatum::typlen, PLyObToDatum::typmod, PLyObToDatum::typoid, PLyObToTransform::typtransform, TypeCacheEntry::typtype, and PLyObToDatum::u.

Referenced by PLy_exec_trigger(), PLy_output_setup_func(), PLy_output_setup_tuple(), PLy_procedure_create(), and PLy_spi_prepare().

298 {
299  TypeCacheEntry *typentry;
300  char typtype;
301  Oid trfuncid;
302  Oid typinput;
303 
304  /* Since this is recursive, it could theoretically be driven to overflow */
306 
307  arg->typoid = typeOid;
308  arg->typmod = typmod;
309  arg->mcxt = arg_mcxt;
310 
311  /*
312  * Fetch typcache entry for the target type, asking for whatever info
313  * we'll need later. RECORD is a special case: just treat it as composite
314  * without bothering with the typcache entry.
315  */
316  if (typeOid != RECORDOID)
317  {
318  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
319  typtype = typentry->typtype;
320  arg->typbyval = typentry->typbyval;
321  arg->typlen = typentry->typlen;
322  arg->typalign = typentry->typalign;
323  }
324  else
325  {
326  typentry = NULL;
327  typtype = TYPTYPE_COMPOSITE;
328  /* hard-wired knowledge about type RECORD: */
329  arg->typbyval = false;
330  arg->typlen = -1;
331  arg->typalign = 'd';
332  }
333 
334  /*
335  * Choose conversion method. Note that transform functions are checked
336  * for composite and scalar types, but not for arrays or domains. This is
337  * somewhat historical, but we'd have a problem allowing them on domains,
338  * since we drill down through all levels of a domain nest without looking
339  * at the intermediate levels at all.
340  */
341  if (typtype == TYPTYPE_DOMAIN)
342  {
343  /* Domain */
344  arg->func = PLyObject_ToDomain;
345  arg->u.domain.domain_info = NULL;
346  /* Recursively set up conversion info for the element type */
347  arg->u.domain.base = (PLyObToDatum *)
348  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
349  PLy_output_setup_func(arg->u.domain.base, arg_mcxt,
350  typentry->domainBaseType,
351  typentry->domainBaseTypmod,
352  proc);
353  }
354  else if (typentry &&
355  OidIsValid(typentry->typelem) && typentry->typlen == -1)
356  {
357  /* Standard varlena array (cf. get_element_type) */
358  arg->func = PLySequence_ToArray;
359  /* Get base type OID to insert into constructed array */
360  /* (note this might not be the same as the immediate child type) */
361  arg->u.array.elmbasetype = getBaseType(typentry->typelem);
362  /* Recursively set up conversion info for the element type */
363  arg->u.array.elm = (PLyObToDatum *)
364  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
365  PLy_output_setup_func(arg->u.array.elm, arg_mcxt,
366  typentry->typelem, typmod,
367  proc);
368  }
369  else if ((trfuncid = get_transform_tosql(typeOid,
370  proc->langid,
371  proc->trftypes)))
372  {
374  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
375  }
376  else if (typtype == TYPTYPE_COMPOSITE)
377  {
378  /* Named composite type, or RECORD */
380  /* We'll set up the per-field data later */
381  arg->u.tuple.recdesc = NULL;
382  arg->u.tuple.typentry = typentry;
384  arg->u.tuple.atts = NULL;
385  arg->u.tuple.natts = 0;
386  /* Mark this invalid till needed, too */
388  }
389  else
390  {
391  /* Scalar type, but we have a couple of special cases */
392  switch (typeOid)
393  {
394  case BOOLOID:
395  arg->func = PLyObject_ToBool;
396  break;
397  case BYTEAOID:
398  arg->func = PLyObject_ToBytea;
399  break;
400  default:
401  arg->func = PLyObject_ToScalar;
402  getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam);
403  fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt);
404  break;
405  }
406  }
407 }
void * domain_info
Definition: plpy_typeio.h:122
FmgrInfo typfunc
Definition: plpy_typeio.h:95
unsigned int Oid
Definition: postgres_ext.h:31
int16 typlen
Definition: typcache.h:37
#define OidIsValid(objectId)
Definition: c.h:645
bool typbyval
Definition: typcache.h:38
PLyObToTransform transform
Definition: plpy_typeio.h:145
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:146
PLyObToDatum * base
Definition: plpy_typeio.h:121
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
PLyObToDomain domain
Definition: plpy_typeio.h:144
Oid domainBaseType
Definition: typcache.h:105
static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1081
PLyObToArray array
Definition: plpy_typeio.h:142
TupleDesc recdesc
Definition: plpy_typeio.h:108
uint64 tupdescid
Definition: plpy_typeio.h:111
PLyObToScalar scalar
Definition: plpy_typeio.h:141
void check_stack_depth(void)
Definition: postgres.c:3284
static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1106
static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:878
int32 domainBaseTypmod
Definition: typcache.h:106
FmgrInfo typtransform
Definition: plpy_typeio.h:127
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:134
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2641
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:940
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:140
TypeCacheEntry * typentry
Definition: plpy_typeio.h:110
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:322
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
char typtype
Definition: typcache.h:41
PLyObToDatum * elm
Definition: plpy_typeio.h:101
MemoryContext mcxt
Definition: plpy_typeio.h:138
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1921
static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1123
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:295
PLyObToTuple tuple
Definition: plpy_typeio.h:143
char typalign
Definition: typcache.h:39
static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1140
PLyObToDatum * atts
Definition: plpy_typeio.h:113
static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:896
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2299
FmgrInfo recinfunc
Definition: plpy_typeio.h:116
union PLyObToDatum::@166 u

◆ PLy_output_setup_record()

void PLy_output_setup_record ( PLyObToDatum arg,
TupleDesc  desc,
PLyProcedure proc 
)

Definition at line 260 of file plpy_typeio.c.

References Assert, BlessTupleDesc(), PLy_output_setup_tuple(), PLyObToTuple::recdesc, TupleDescData::tdtypeid, TupleDescData::tdtypmod, PLyObToDatum::tuple, PLyObToDatum::typmod, PLyObToDatum::typoid, and PLyObToDatum::u.

Referenced by PLy_function_build_args().

261 {
262  /* Makes no sense unless RECORD */
263  Assert(arg->typoid == RECORDOID);
264  Assert(desc->tdtypeid == RECORDOID);
265 
266  /*
267  * Bless the record type if not already done. We'd have to do this anyway
268  * to return a tuple, so we might as well force the issue so we can use
269  * the known-record-type code path.
270  */
271  BlessTupleDesc(desc);
272 
273  /*
274  * Update arg->typmod, and clear the recdesc link if it's changed. The
275  * next call of PLyObject_ToComposite will look up a long-lived tupdesc
276  * for the record type.
277  */
278  arg->typmod = desc->tdtypmod;
279  if (arg->u.tuple.recdesc &&
280  arg->u.tuple.recdesc->tdtypmod != arg->typmod)
281  arg->u.tuple.recdesc = NULL;
282 
283  /* Update derived data if necessary */
284  PLy_output_setup_tuple(arg, desc, proc);
285 }
TupleDesc recdesc
Definition: plpy_typeio.h:108
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:214
#define Assert(condition)
Definition: c.h:739
Oid tdtypeid
Definition: tupdesc.h:82
PLyObToTuple tuple
Definition: plpy_typeio.h:143
union PLyObToDatum::@166 u

◆ PLy_output_setup_tuple()

void PLy_output_setup_tuple ( PLyObToDatum arg,
TupleDesc  desc,
PLyProcedure proc 
)

Definition at line 214 of file plpy_typeio.c.

References Assert, PLyObToTuple::atts, PLyObToDatum::func, i, PLyObToDatum::mcxt, MemoryContextAllocZero(), TupleDescData::natts, PLyObToTuple::natts, pfree(), PLy_output_setup_func(), PLyObject_ToComposite(), PLyObToTuple::recdesc, PLyObToDatum::tuple, TupleDescAttr, PLyObToDatum::typmod, PLyObToDatum::typoid, and PLyObToDatum::u.

Referenced by PLy_exec_trigger(), PLy_output_setup_record(), and PLyObject_ToComposite().

215 {
216  int i;
217 
218  /* We should be working on a previously-set-up struct */
220 
221  /* Save pointer to tupdesc, but only if this is an anonymous record type */
222  if (arg->typoid == RECORDOID && arg->typmod < 0)
223  arg->u.tuple.recdesc = desc;
224 
225  /* (Re)allocate atts array as needed */
226  if (arg->u.tuple.natts != desc->natts)
227  {
228  if (arg->u.tuple.atts)
229  pfree(arg->u.tuple.atts);
230  arg->u.tuple.natts = desc->natts;
231  arg->u.tuple.atts = (PLyObToDatum *)
233  desc->natts * sizeof(PLyObToDatum));
234  }
235 
236  /* Fill the atts entries, except for dropped columns */
237  for (i = 0; i < desc->natts; i++)
238  {
239  Form_pg_attribute attr = TupleDescAttr(desc, i);
240  PLyObToDatum *att = &arg->u.tuple.atts[i];
241 
242  if (attr->attisdropped)
243  continue;
244 
245  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
246  continue; /* already set up this entry */
247 
248  PLy_output_setup_func(att, arg->mcxt,
249  attr->atttypid, attr->atttypmod,
250  proc);
251  }
252 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
void pfree(void *pointer)
Definition: mcxt.c:1056
TupleDesc recdesc
Definition: plpy_typeio.h:108
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:940
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define Assert(condition)
Definition: c.h:739
MemoryContext mcxt
Definition: plpy_typeio.h:138
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:295
PLyObToTuple tuple
Definition: plpy_typeio.h:143
int i
PLyObToDatum * atts
Definition: plpy_typeio.h:113
union PLyObToDatum::@166 u

◆ PLyBool_FromBool()

static PyObject * PLyBool_FromBool ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 549 of file plpy_typeio.c.

References DatumGetBool.

Referenced by PLy_input_setup_func().

550 {
551  if (DatumGetBool(d))
552  Py_RETURN_TRUE;
553  Py_RETURN_FALSE;
554 }
#define DatumGetBool(X)
Definition: postgres.h:393

◆ PLyBytes_FromBytea()

static PyObject * PLyBytes_FromBytea ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 627 of file plpy_typeio.c.

References DatumGetByteaPP, PyBytes_FromStringAndSize, generate_unaccent_rules::str, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by PLy_input_setup_func().

628 {
629  text *txt = DatumGetByteaPP(d);
630  char *str = VARDATA_ANY(txt);
631  size_t size = VARSIZE_ANY_EXHDR(txt);
632 
633  return PyBytes_FromStringAndSize(str, size);
634 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
#define PyBytes_FromStringAndSize
Definition: plpython.h:87
#define DatumGetByteaPP(X)
Definition: fmgr.h:285
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
Definition: c.h:556

◆ PLyDecimal_FromNumeric()

static PyObject * PLyDecimal_FromNumeric ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 569 of file plpy_typeio.c.

References DatumGetCString, decimal_constructor, DirectFunctionCall1, ERROR, numeric_out(), PLy_elog, and generate_unaccent_rules::str.

Referenced by PLy_input_setup_func().

570 {
571  static PyObject *decimal_constructor;
572  char *str;
573  PyObject *pyvalue;
574 
575  /* Try to import cdecimal. If it doesn't exist, fall back to decimal. */
576  if (!decimal_constructor)
577  {
578  PyObject *decimal_module;
579 
580  decimal_module = PyImport_ImportModule("cdecimal");
581  if (!decimal_module)
582  {
583  PyErr_Clear();
584  decimal_module = PyImport_ImportModule("decimal");
585  }
586  if (!decimal_module)
587  PLy_elog(ERROR, "could not import a module for Decimal constructor");
588 
589  decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
590  if (!decimal_constructor)
591  PLy_elog(ERROR, "no Decimal attribute in module");
592  }
593 
595  pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
596  if (!pyvalue)
597  PLy_elog(ERROR, "conversion from numeric to Decimal failed");
598 
599  return pyvalue;
600 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:655
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:615
#define ERROR
Definition: elog.h:43
static PyObject * decimal_constructor
#define DatumGetCString(X)
Definition: postgres.h:566
#define PLy_elog

◆ PLyDict_FromComposite()

static PyObject * PLyDict_FromComposite ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 780 of file plpy_typeio.c.

References DatumGetHeapTupleHeader, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, lookup_rowtype_tupdesc(), PLy_current_execution_context(), PLy_input_setup_tuple(), PLyDict_FromTuple(), ReleaseTupleDesc, HeapTupleData::t_data, and HeapTupleData::t_len.

Referenced by PLy_input_setup_func(), and PLy_input_setup_tuple().

781 {
782  PyObject *dict;
783  HeapTupleHeader td;
784  Oid tupType;
785  int32 tupTypmod;
786  TupleDesc tupdesc;
787  HeapTupleData tmptup;
788 
789  td = DatumGetHeapTupleHeader(d);
790  /* Extract rowtype info and find a tupdesc */
791  tupType = HeapTupleHeaderGetTypeId(td);
792  tupTypmod = HeapTupleHeaderGetTypMod(td);
793  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
794 
795  /* Set up I/O funcs if not done yet */
796  PLy_input_setup_tuple(arg, tupdesc,
797  PLy_current_execution_context()->curr_proc);
798 
799  /* Build a temporary HeapTuple control structure */
801  tmptup.t_data = td;
802 
803  dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
804 
805  ReleaseTupleDesc(tupdesc);
806 
807  return dict;
808 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1652
unsigned int Oid
Definition: postgres_ext.h:31
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:289
signed int int32
Definition: c.h:347
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:814
uint32 t_len
Definition: htup.h:64
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:164
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ PLyDict_FromTuple()

static PyObject * PLyDict_FromTuple ( PLyDatumToOb arg,
HeapTuple  tuple,
TupleDesc  desc,
bool  include_generated 
)
static

Definition at line 814 of file plpy_typeio.c.

References Assert, PLyTupleToOb::atts, PLyDatumToOb::func, heap_getattr, i, sort-test::key, NameStr, PLyTupleToOb::natts, TupleDescData::natts, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyDatumToOb::tuple, TupleDescAttr, PLyDatumToOb::u, and value.

Referenced by PLy_input_from_tuple(), and PLyDict_FromComposite().

815 {
816  PyObject *volatile dict;
817 
818  /* Simple sanity check that desc matches */
819  Assert(desc->natts == arg->u.tuple.natts);
820 
821  dict = PyDict_New();
822  if (dict == NULL)
823  return NULL;
824 
825  PG_TRY();
826  {
827  int i;
828 
829  for (i = 0; i < arg->u.tuple.natts; i++)
830  {
831  PLyDatumToOb *att = &arg->u.tuple.atts[i];
832  Form_pg_attribute attr = TupleDescAttr(desc, i);
833  char *key;
834  Datum vattr;
835  bool is_null;
836  PyObject *value;
837 
838  if (attr->attisdropped)
839  continue;
840 
841  if (attr->attgenerated)
842  {
843  /* don't include unless requested */
844  if (!include_generated)
845  continue;
846  }
847 
848  key = NameStr(attr->attname);
849  vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
850 
851  if (is_null)
852  PyDict_SetItemString(dict, key, Py_None);
853  else
854  {
855  value = att->func(att, vattr);
856  PyDict_SetItemString(dict, key, value);
857  Py_DECREF(value);
858  }
859  }
860  }
861  PG_CATCH();
862  {
863  Py_DECREF(dict);
864  PG_RE_THROW();
865  }
866  PG_END_TRY();
867 
868  return dict;
869 }
PLyDatumToOb * atts
Definition: plpy_typeio.h:48
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @145 value
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
#define PG_RE_THROW()
Definition: elog.h:363
int i
#define NameStr(name)
Definition: c.h:616
union PLyDatumToOb::@165 u
#define PG_TRY()
Definition: elog.h:322
PLyTupleToOb tuple
Definition: plpy_typeio.h:70
#define PG_END_TRY()
Definition: elog.h:347

◆ PLyFloat_FromFloat4()

static PyObject * PLyFloat_FromFloat4 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 557 of file plpy_typeio.c.

References DatumGetFloat4().

Referenced by PLy_input_setup_func().

558 {
559  return PyFloat_FromDouble(DatumGetFloat4(d));
560 }
static float4 DatumGetFloat4(Datum X)
Definition: postgres.h:664

◆ PLyFloat_FromFloat8()

static PyObject * PLyFloat_FromFloat8 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 563 of file plpy_typeio.c.

References DatumGetFloat8.

Referenced by PLy_input_setup_func().

564 {
565  return PyFloat_FromDouble(DatumGetFloat8(d));
566 }
#define DatumGetFloat8(X)
Definition: postgres.h:714

◆ PLyGenericObject_ToComposite()

static Datum PLyGenericObject_ToComposite ( PLyObToDatum arg,
TupleDesc  desc,
PyObject *  object,
bool  inarray 
)
static

Definition at line 1495 of file plpy_typeio.c.

References PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, sort-test::key, NameStr, TupleDescData::natts, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyObToDatum::tuple, TupleDescAttr, PLyObToDatum::u, value, and values.

Referenced by PLyObject_ToComposite().

1496 {
1497  Datum result;
1498  HeapTuple tuple;
1499  Datum *values;
1500  bool *nulls;
1501  volatile int i;
1502 
1503  /* Build tuple */
1504  values = palloc(sizeof(Datum) * desc->natts);
1505  nulls = palloc(sizeof(bool) * desc->natts);
1506  for (i = 0; i < desc->natts; ++i)
1507  {
1508  char *key;
1509  PyObject *volatile value;
1510  PLyObToDatum *att;
1511  Form_pg_attribute attr = TupleDescAttr(desc, i);
1512 
1513  if (attr->attisdropped)
1514  {
1515  values[i] = (Datum) 0;
1516  nulls[i] = true;
1517  continue;
1518  }
1519 
1520  key = NameStr(attr->attname);
1521  value = NULL;
1522  att = &arg->u.tuple.atts[i];
1523  PG_TRY();
1524  {
1525  value = PyObject_GetAttrString(object, key);
1526  if (!value)
1527  {
1528  /*
1529  * No attribute for this column in the object.
1530  *
1531  * If we are parsing a composite type in an array, a likely
1532  * cause is that the function contained something like "[[123,
1533  * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1534  * array, with a composite type (123, 'foo') in it. But now
1535  * it's interpreted as a two-dimensional array, and we try to
1536  * interpret "123" as the composite type. See also similar
1537  * heuristic in PLyObject_ToScalar().
1538  */
1539  ereport(ERROR,
1540  (errcode(ERRCODE_UNDEFINED_COLUMN),
1541  errmsg("attribute \"%s\" does not exist in Python object", key),
1542  inarray ?
1543  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".") :
1544  errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1545  }
1546 
1547  values[i] = att->func(att, value, &nulls[i], false);
1548 
1549  Py_XDECREF(value);
1550  value = NULL;
1551  }
1552  PG_CATCH();
1553  {
1554  Py_XDECREF(value);
1555  PG_RE_THROW();
1556  }
1557  PG_END_TRY();
1558  }
1559 
1560  tuple = heap_form_tuple(desc, values, nulls);
1561  result = heap_copy_tuple_as_datum(tuple, desc);
1562  heap_freetuple(tuple);
1563 
1564  pfree(values);
1565  pfree(nulls);
1566 
1567  return result;
1568 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @145 value
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
uintptr_t Datum
Definition: postgres.h:367
#define PG_CATCH()
Definition: elog.h:332
#define PG_RE_THROW()
Definition: elog.h:363
static Datum values[MAXATTR]
Definition: bootstrap.c:167
PLyObToTuple tuple
Definition: plpy_typeio.h:143
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define NameStr(name)
Definition: c.h:616
PLyObToDatum * atts
Definition: plpy_typeio.h:113
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347
union PLyObToDatum::@166 u

◆ PLyInt_FromInt16()

static PyObject * PLyInt_FromInt16 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 603 of file plpy_typeio.c.

References DatumGetInt16.

Referenced by PLy_input_setup_func().

604 {
605  return PyInt_FromLong(DatumGetInt16(d));
606 }
#define DatumGetInt16(X)
Definition: postgres.h:444

◆ PLyInt_FromInt32()

static PyObject * PLyInt_FromInt32 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 609 of file plpy_typeio.c.

References DatumGetInt32.

Referenced by PLy_input_setup_func().

610 {
611  return PyInt_FromLong(DatumGetInt32(d));
612 }
#define DatumGetInt32(X)
Definition: postgres.h:472

◆ PLyList_FromArray()

static PyObject * PLyList_FromArray ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 666 of file plpy_typeio.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_NULLBITMAP, PLyDatumToOb::array, Assert, DatumGetArrayTypeP, PLyArrayToOb::elm, MAXDIM, PLyList_FromArray_recurse(), and PLyDatumToOb::u.

Referenced by PLy_input_setup_func().

667 {
668  ArrayType *array = DatumGetArrayTypeP(d);
669  PLyDatumToOb *elm = arg->u.array.elm;
670  int ndim;
671  int *dims;
672  char *dataptr;
673  bits8 *bitmap;
674  int bitmask;
675 
676  if (ARR_NDIM(array) == 0)
677  return PyList_New(0);
678 
679  /* Array dimensions and left bounds */
680  ndim = ARR_NDIM(array);
681  dims = ARR_DIMS(array);
682  Assert(ndim < MAXDIM);
683 
684  /*
685  * We iterate the SQL array in the physical order it's stored in the
686  * datum. For example, for a 3-dimensional array the order of iteration
687  * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0]
688  * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till
689  * [1,m,k], and so on.
690  *
691  * In Python, there are no multi-dimensional lists as such, but they are
692  * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
693  * list of n m-element arrays, each element of which is k-element array.
694  * PLyList_FromArray_recurse() builds the Python list for a single
695  * dimension, and recurses for the next inner dimension.
696  */
697  dataptr = ARR_DATA_PTR(array);
698  bitmap = ARR_NULLBITMAP(array);
699  bitmask = 1;
700 
701  return PLyList_FromArray_recurse(elm, dims, ndim, 0,
702  &dataptr, &bitmap, &bitmask);
703 }
#define MAXDIM
Definition: c.h:536
PLyArrayToOb array
Definition: plpy_typeio.h:69
#define ARR_DIMS(a)
Definition: array.h:282
#define ARR_DATA_PTR(a)
Definition: array.h:310
PLyDatumToOb * elm
Definition: plpy_typeio.h:37
uint8 bits8
Definition: c.h:366
#define Assert(condition)
Definition: c.h:739
#define ARR_NDIM(a)
Definition: array.h:278
static PyObject * PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
Definition: plpy_typeio.c:706
union PLyDatumToOb::@165 u
#define ARR_NULLBITMAP(a)
Definition: array.h:288
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ PLyList_FromArray_recurse()

static PyObject * PLyList_FromArray_recurse ( PLyDatumToOb elm,
int *  dims,
int  ndim,
int  dim,
char **  dataptr_p,
bits8 **  bitmap_p,
int *  bitmask_p 
)
static

Definition at line 706 of file plpy_typeio.c.

References att_addlength_pointer, att_align_nominal, fetch_att, PLyDatumToOb::func, i, sort-test::list, PLyDatumToOb::typalign, PLyDatumToOb::typbyval, and PLyDatumToOb::typlen.

Referenced by PLyList_FromArray().

708 {
709  int i;
710  PyObject *list;
711 
712  list = PyList_New(dims[dim]);
713  if (!list)
714  return NULL;
715 
716  if (dim < ndim - 1)
717  {
718  /* Outer dimension. Recurse for each inner slice. */
719  for (i = 0; i < dims[dim]; i++)
720  {
721  PyObject *sublist;
722 
723  sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
724  dataptr_p, bitmap_p, bitmask_p);
725  PyList_SET_ITEM(list, i, sublist);
726  }
727  }
728  else
729  {
730  /*
731  * Innermost dimension. Fill the list with the values from the array
732  * for this slice.
733  */
734  char *dataptr = *dataptr_p;
735  bits8 *bitmap = *bitmap_p;
736  int bitmask = *bitmask_p;
737 
738  for (i = 0; i < dims[dim]; i++)
739  {
740  /* checking for NULL */
741  if (bitmap && (*bitmap & bitmask) == 0)
742  {
743  Py_INCREF(Py_None);
744  PyList_SET_ITEM(list, i, Py_None);
745  }
746  else
747  {
748  Datum itemvalue;
749 
750  itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
751  PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
752  dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
753  dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
754  }
755 
756  /* advance bitmap pointer if any */
757  if (bitmap)
758  {
759  bitmask <<= 1;
760  if (bitmask == 0x100 /* (1<<8) */ )
761  {
762  bitmap++;
763  bitmask = 1;
764  }
765  }
766  }
767 
768  *dataptr_p = dataptr;
769  *bitmap_p = bitmap;
770  *bitmask_p = bitmask;
771  }
772 
773  return list;
774 }
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:146
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
int16 typlen
Definition: plpy_typeio.h:63
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:174
uint8 bits8
Definition: c.h:366
uintptr_t Datum
Definition: postgres.h:367
#define fetch_att(T, attbyval, attlen)
Definition: tupmacs.h:73
int i
static PyObject * PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
Definition: plpy_typeio.c:706

◆ PLyLong_FromInt64()

static PyObject * PLyLong_FromInt64 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 615 of file plpy_typeio.c.

References DatumGetInt64.

Referenced by PLy_input_setup_func().

616 {
617  return PyLong_FromLongLong(DatumGetInt64(d));
618 }
#define DatumGetInt64(X)
Definition: postgres.h:607

◆ PLyLong_FromOid()

static PyObject * PLyLong_FromOid ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 621 of file plpy_typeio.c.

References DatumGetObjectId.

Referenced by PLy_input_setup_func().

622 {
623  return PyLong_FromUnsignedLong(DatumGetObjectId(d));
624 }
#define DatumGetObjectId(X)
Definition: postgres.h:500

◆ PLyMapping_ToComposite()

static Datum PLyMapping_ToComposite ( PLyObToDatum arg,
TupleDesc  desc,
PyObject *  mapping 
)
static

Definition at line 1353 of file plpy_typeio.c.

References Assert, PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, sort-test::key, NameStr, TupleDescData::natts, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyObToDatum::tuple, TupleDescAttr, PLyObToDatum::u, value, and values.

Referenced by PLyObject_ToComposite().

1354 {
1355  Datum result;
1356  HeapTuple tuple;
1357  Datum *values;
1358  bool *nulls;
1359  volatile int i;
1360 
1361  Assert(PyMapping_Check(mapping));
1362 
1363  /* Build tuple */
1364  values = palloc(sizeof(Datum) * desc->natts);
1365  nulls = palloc(sizeof(bool) * desc->natts);
1366  for (i = 0; i < desc->natts; ++i)
1367  {
1368  char *key;
1369  PyObject *volatile value;
1370  PLyObToDatum *att;
1371  Form_pg_attribute attr = TupleDescAttr(desc, i);
1372 
1373  if (attr->attisdropped)
1374  {
1375  values[i] = (Datum) 0;
1376  nulls[i] = true;
1377  continue;
1378  }
1379 
1380  key = NameStr(attr->attname);
1381  value = NULL;
1382  att = &arg->u.tuple.atts[i];
1383  PG_TRY();
1384  {
1385  value = PyMapping_GetItemString(mapping, key);
1386  if (!value)
1387  ereport(ERROR,
1388  (errcode(ERRCODE_UNDEFINED_COLUMN),
1389  errmsg("key \"%s\" not found in mapping", key),
1390  errhint("To return null in a column, "
1391  "add the value None to the mapping with the key named after the column.")));
1392 
1393  values[i] = att->func(att, value, &nulls[i], false);
1394 
1395  Py_XDECREF(value);
1396  value = NULL;
1397  }
1398  PG_CATCH();
1399  {
1400  Py_XDECREF(value);
1401  PG_RE_THROW();
1402  }
1403  PG_END_TRY();
1404  }
1405 
1406  tuple = heap_form_tuple(desc, values, nulls);
1407  result = heap_copy_tuple_as_datum(tuple, desc);
1408  heap_freetuple(tuple);
1409 
1410  pfree(values);
1411  pfree(nulls);
1412 
1413  return result;
1414 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @145 value
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
uintptr_t Datum
Definition: postgres.h:367
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
#define PG_RE_THROW()
Definition: elog.h:363
static Datum values[MAXATTR]
Definition: bootstrap.c:167
PLyObToTuple tuple
Definition: plpy_typeio.h:143
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define NameStr(name)
Definition: c.h:616
PLyObToDatum * atts
Definition: plpy_typeio.h:113
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347
union PLyObToDatum::@166 u

◆ PLyObject_AsString()

char* PLyObject_AsString ( PyObject *  plrv)

Definition at line 1023 of file plpy_typeio.c.

References elog, ereport, errcode(), errmsg(), ERROR, pg_verifymbstr(), PLy_elog, PLyUnicode_Bytes(), pstrdup(), PyBytes_AsString, and PyBytes_Size.

Referenced by PLyObject_ToScalar(), and PLyString_ToComposite().

1024 {
1025  PyObject *plrv_bo;
1026  char *plrv_sc;
1027  size_t plen;
1028  size_t slen;
1029 
1030  if (PyUnicode_Check(plrv))
1031  plrv_bo = PLyUnicode_Bytes(plrv);
1032  else if (PyFloat_Check(plrv))
1033  {
1034  /* use repr() for floats, str() is lossy */
1035 #if PY_MAJOR_VERSION >= 3
1036  PyObject *s = PyObject_Repr(plrv);
1037 
1038  plrv_bo = PLyUnicode_Bytes(s);
1039  Py_XDECREF(s);
1040 #else
1041  plrv_bo = PyObject_Repr(plrv);
1042 #endif
1043  }
1044  else
1045  {
1046 #if PY_MAJOR_VERSION >= 3
1047  PyObject *s = PyObject_Str(plrv);
1048 
1049  plrv_bo = PLyUnicode_Bytes(s);
1050  Py_XDECREF(s);
1051 #else
1052  plrv_bo = PyObject_Str(plrv);
1053 #endif
1054  }
1055  if (!plrv_bo)
1056  PLy_elog(ERROR, "could not create string representation of Python object");
1057 
1058  plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
1059  plen = PyBytes_Size(plrv_bo);
1060  slen = strlen(plrv_sc);
1061 
1062  Py_XDECREF(plrv_bo);
1063 
1064  if (slen < plen)
1065  ereport(ERROR,
1066  (errcode(ERRCODE_DATATYPE_MISMATCH),
1067  errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
1068  else if (slen > plen)
1069  elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
1070  pg_verifymbstr(plrv_sc, slen, false);
1071 
1072  return plrv_sc;
1073 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int errcode(int sqlerrcode)
Definition: elog.c:608
#define PyBytes_AsString
Definition: plpython.h:86
#define ERROR
Definition: elog.h:43
#define PLy_elog
#define ereport(elevel, rest)
Definition: elog.h:141
#define PyBytes_Size
Definition: plpython.h:88
PyObject * PLyUnicode_Bytes(PyObject *unicode)
Definition: plpy_util.c:21
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1914

◆ PLyObject_FromTransform()

static PyObject * PLyObject_FromTransform ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 654 of file plpy_typeio.c.

References DatumGetPointer, FunctionCall1, PLyDatumToOb::transform, PLyTransformToOb::typtransform, and PLyDatumToOb::u.

Referenced by PLy_input_setup_func().

655 {
656  Datum t;
657 
658  t = FunctionCall1(&arg->u.transform.typtransform, d);
659  return (PyObject *) DatumGetPointer(t);
660 }
FmgrInfo typtransform
Definition: plpy_typeio.h:54
PLyTransformToOb transform
Definition: plpy_typeio.h:71
uintptr_t Datum
Definition: postgres.h:367
#define DatumGetPointer(X)
Definition: postgres.h:549
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:633
union PLyDatumToOb::@165 u

◆ PLyObject_ToBool()

static Datum PLyObject_ToBool ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 878 of file plpy_typeio.c.

References BoolGetDatum.

Referenced by PLy_output_setup_func().

880 {
881  if (plrv == Py_None)
882  {
883  *isnull = true;
884  return (Datum) 0;
885  }
886  *isnull = false;
887  return BoolGetDatum(PyObject_IsTrue(plrv));
888 }
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402

◆ PLyObject_ToBytea()

static Datum PLyObject_ToBytea ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 896 of file plpy_typeio.c.

References ERROR, palloc(), PG_END_TRY, PG_FINALLY, PG_TRY, PLy_elog, PointerGetDatum, PyBytes_AsString, PyBytes_Size, PyObject_Bytes, SET_VARSIZE, VARDATA, and VARHDRSZ.

Referenced by PLy_output_setup_func().

898 {
899  PyObject *volatile plrv_so = NULL;
900  Datum rv = (Datum) 0;
901 
902  if (plrv == Py_None)
903  {
904  *isnull = true;
905  return (Datum) 0;
906  }
907  *isnull = false;
908 
909  plrv_so = PyObject_Bytes(plrv);
910  if (!plrv_so)
911  PLy_elog(ERROR, "could not create bytes representation of Python object");
912 
913  PG_TRY();
914  {
915  char *plrv_sc = PyBytes_AsString(plrv_so);
916  size_t len = PyBytes_Size(plrv_so);
917  size_t size = len + VARHDRSZ;
918  bytea *result = palloc(size);
919 
920  SET_VARSIZE(result, size);
921  memcpy(VARDATA(result), plrv_sc, len);
922  rv = PointerGetDatum(result);
923  }
924  PG_FINALLY();
925  {
926  Py_XDECREF(plrv_so);
927  }
928  PG_END_TRY();
929 
930  return rv;
931 }
#define VARDATA(PTR)
Definition: postgres.h:302
#define PyObject_Bytes
Definition: plpython.h:89
#define PointerGetDatum(X)
Definition: postgres.h:556
#define VARHDRSZ
Definition: c.h:562
#define PyBytes_AsString
Definition: plpython.h:86
#define ERROR
Definition: elog.h:43
#define PLy_elog
#define PyBytes_Size
Definition: plpython.h:88
#define PG_FINALLY()
Definition: elog.h:339
uintptr_t Datum
Definition: postgres.h:367
void * palloc(Size size)
Definition: mcxt.c:949
Definition: c.h:556
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347

◆ PLyObject_ToComposite()

static Datum PLyObject_ToComposite ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 940 of file plpy_typeio.c.

References Assert, lookup_rowtype_tupdesc(), TupleDescData::natts, PLyObToTuple::natts, PinTupleDesc, PLy_current_execution_context(), PLy_output_setup_tuple(), PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), PLySequence_ToComposite(), PLyString_ToComposite(), PLyObToTuple::recdesc, ReleaseTupleDesc, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, PLyObToTuple::tupdescid, PLyObToDatum::tuple, PLyObToTuple::typentry, PLyObToDatum::typmod, PLyObToDatum::typoid, and PLyObToDatum::u.

Referenced by PLy_output_setup_func(), and PLy_output_setup_tuple().

942 {
943  Datum rv;
944  TupleDesc desc;
945 
946  if (plrv == Py_None)
947  {
948  *isnull = true;
949  return (Datum) 0;
950  }
951  *isnull = false;
952 
953  /*
954  * The string conversion case doesn't require a tupdesc, nor per-field
955  * conversion data, so just go for it if that's the case to use.
956  */
957  if (PyString_Check(plrv) || PyUnicode_Check(plrv))
958  return PLyString_ToComposite(arg, plrv, inarray);
959 
960  /*
961  * If we're dealing with a named composite type, we must look up the
962  * tupdesc every time, to protect against possible changes to the type.
963  * RECORD types can't change between calls; but we must still be willing
964  * to set up the info the first time, if nobody did yet.
965  */
966  if (arg->typoid != RECORDOID)
967  {
968  desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
969  /* We should have the descriptor of the type's typcache entry */
970  Assert(desc == arg->u.tuple.typentry->tupDesc);
971  /* Detect change of descriptor, update cache if needed */
972  if (arg->u.tuple.tupdescid != arg->u.tuple.typentry->tupDesc_identifier)
973  {
974  PLy_output_setup_tuple(arg, desc,
975  PLy_current_execution_context()->curr_proc);
977  }
978  }
979  else
980  {
981  desc = arg->u.tuple.recdesc;
982  if (desc == NULL)
983  {
984  desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
985  arg->u.tuple.recdesc = desc;
986  }
987  else
988  {
989  /* Pin descriptor to match unpin below */
990  PinTupleDesc(desc);
991  }
992  }
993 
994  /* Simple sanity check on our caching */
995  Assert(desc->natts == arg->u.tuple.natts);
996 
997  /*
998  * Convert, using the appropriate method depending on the type of the
999  * supplied Python object.
1000  */
1001  if (PySequence_Check(plrv))
1002  /* composite type as sequence (tuple, list etc) */
1003  rv = PLySequence_ToComposite(arg, desc, plrv);
1004  else if (PyMapping_Check(plrv))
1005  /* composite type as mapping (currently only dict) */
1006  rv = PLyMapping_ToComposite(arg, desc, plrv);
1007  else
1008  /* returned as smth, must provide method __getattr__(name) */
1009  rv = PLyGenericObject_ToComposite(arg, desc, plrv, inarray);
1010 
1011  ReleaseTupleDesc(desc);
1012 
1013  return rv;
1014 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1652
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
TupleDesc recdesc
Definition: plpy_typeio.h:108
uint64 tupdescid
Definition: plpy_typeio.h:111
static Datum PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
Definition: plpy_typeio.c:1495
TypeCacheEntry * typentry
Definition: plpy_typeio.h:110
uintptr_t Datum
Definition: postgres.h:367
void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:214
static Datum PLyString_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray)
Definition: plpy_typeio.c:1292
#define Assert(condition)
Definition: c.h:739
uint64 tupDesc_identifier
Definition: typcache.h:87
#define PinTupleDesc(tupdesc)
Definition: tupdesc.h:116
PLyObToTuple tuple
Definition: plpy_typeio.h:143
static Datum PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
Definition: plpy_typeio.c:1418
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
static Datum PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
Definition: plpy_typeio.c:1353
TupleDesc tupDesc
Definition: typcache.h:86
union PLyObToDatum::@166 u

◆ PLyObject_ToDomain()

static Datum PLyObject_ToDomain ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 1106 of file plpy_typeio.c.

References PLyObToDomain::base, PLyObToDatum::domain, domain_check(), PLyObToDomain::domain_info, PLyObToDatum::func, PLyObToDatum::mcxt, PLyObToDatum::typoid, and PLyObToDatum::u.

Referenced by PLy_output_setup_func().

1108 {
1109  Datum result;
1110  PLyObToDatum *base = arg->u.domain.base;
1111 
1112  result = base->func(base, plrv, isnull, inarray);
1113  domain_check(result, *isnull, arg->typoid,
1114  &arg->u.domain.domain_info, arg->mcxt);
1115  return result;
1116 }
void * domain_info
Definition: plpy_typeio.h:122
PLyObToDatum * base
Definition: plpy_typeio.h:121
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
PLyObToDomain domain
Definition: plpy_typeio.h:144
uintptr_t Datum
Definition: postgres.h:367
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:327
MemoryContext mcxt
Definition: plpy_typeio.h:138
union PLyObToDatum::@166 u

◆ PLyObject_ToScalar()

static Datum PLyObject_ToScalar ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 1081 of file plpy_typeio.c.

References InputFunctionCall(), PLyObject_AsString(), PLyObToDatum::scalar, generate_unaccent_rules::str, PLyObToScalar::typfunc, PLyObToScalar::typioparam, PLyObToDatum::typmod, and PLyObToDatum::u.

Referenced by PLy_output_setup_func().

1083 {
1084  char *str;
1085 
1086  if (plrv == Py_None)
1087  {
1088  *isnull = true;
1089  return (Datum) 0;
1090  }
1091  *isnull = false;
1092 
1093  str = PLyObject_AsString(plrv);
1094 
1095  return InputFunctionCall(&arg->u.scalar.typfunc,
1096  str,
1097  arg->u.scalar.typioparam,
1098  arg->typmod);
1099 }
FmgrInfo typfunc
Definition: plpy_typeio.h:95
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:1023
PLyObToScalar scalar
Definition: plpy_typeio.h:141
uintptr_t Datum
Definition: postgres.h:367
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1531
union PLyObToDatum::@166 u

◆ PLyObject_ToTransform()

static Datum PLyObject_ToTransform ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 1123 of file plpy_typeio.c.

References FunctionCall1, PointerGetDatum, PLyObToDatum::transform, PLyObToTransform::typtransform, and PLyObToDatum::u.

Referenced by PLy_output_setup_func().

1125 {
1126  if (plrv == Py_None)
1127  {
1128  *isnull = true;
1129  return (Datum) 0;
1130  }
1131  *isnull = false;
1132  return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
1133 }
#define PointerGetDatum(X)
Definition: postgres.h:556
PLyObToTransform transform
Definition: plpy_typeio.h:145
FmgrInfo typtransform
Definition: plpy_typeio.h:127
uintptr_t Datum
Definition: postgres.h:367
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:633
union PLyObToDatum::@166 u

◆ PLySequence_ToArray()

static Datum PLySequence_ToArray ( PLyObToDatum arg,
PyObject *  plrv,
bool isnull,
bool  inarray 
)
static

Definition at line 1140 of file plpy_typeio.c.

References PLyObToDatum::array, construct_md_array(), PLyObToArray::elm, PLyObToArray::elmbasetype, ERROR, i, MaxAllocSize, MAXDIM, next, palloc(), PLy_elog, PLySequence_ToArray_recurse(), PointerGetDatum, PLyObToDatum::typalign, PLyObToDatum::typbyval, PLyObToDatum::typlen, and PLyObToDatum::u.

Referenced by PLy_output_setup_func().

1142 {
1143  ArrayType *array;
1144  int i;
1145  Datum *elems;
1146  bool *nulls;
1147  int64 len;
1148  int ndim;
1149  int dims[MAXDIM];
1150  int lbs[MAXDIM];
1151  int currelem;
1152  PyObject *pyptr = plrv;
1153  PyObject *next;
1154 
1155  if (plrv == Py_None)
1156  {
1157  *isnull = true;
1158  return (Datum) 0;
1159  }
1160  *isnull = false;
1161 
1162  /*
1163  * Determine the number of dimensions, and their sizes.
1164  */
1165  ndim = 0;
1166  len = 1;
1167 
1168  Py_INCREF(plrv);
1169 
1170  for (;;)
1171  {
1172  if (!PyList_Check(pyptr))
1173  break;
1174 
1175  if (ndim == MAXDIM)
1176  PLy_elog(ERROR, "number of array dimensions exceeds the maximum allowed (%d)", MAXDIM);
1177 
1178  dims[ndim] = PySequence_Length(pyptr);
1179  if (dims[ndim] < 0)
1180  PLy_elog(ERROR, "could not determine sequence length for function return value");
1181 
1182  if (dims[ndim] > MaxAllocSize)
1183  PLy_elog(ERROR, "array size exceeds the maximum allowed");
1184 
1185  len *= dims[ndim];
1186  if (len > MaxAllocSize)
1187  PLy_elog(ERROR, "array size exceeds the maximum allowed");
1188 
1189  if (dims[ndim] == 0)
1190  {
1191  /* empty sequence */
1192  break;
1193  }
1194 
1195  ndim++;
1196 
1197  next = PySequence_GetItem(pyptr, 0);
1198  Py_XDECREF(pyptr);
1199  pyptr = next;
1200  }
1201  Py_XDECREF(pyptr);
1202 
1203  /*
1204  * Check for zero dimensions. This happens if the object is a tuple or a
1205  * string, rather than a list, or is not a sequence at all. We don't map
1206  * tuples or strings to arrays in general, but in the first level, be
1207  * lenient, for historical reasons. So if the object is a sequence of any
1208  * kind, treat it as a one-dimensional array.
1209  */
1210  if (ndim == 0)
1211  {
1212  if (!PySequence_Check(plrv))
1213  PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");
1214 
1215  ndim = 1;
1216  len = dims[0] = PySequence_Length(plrv);
1217  }
1218 
1219  /*
1220  * Traverse the Python lists, in depth-first order, and collect all the
1221  * elements at the bottom level into 'elems'/'nulls' arrays.
1222  */
1223  elems = palloc(sizeof(Datum) * len);
1224  nulls = palloc(sizeof(bool) * len);
1225  currelem = 0;
1227  dims, ndim, 0,
1228  elems, nulls, &currelem);
1229 
1230  for (i = 0; i < ndim; i++)
1231  lbs[i] = 1;
1232 
1233  array = construct_md_array(elems,
1234  nulls,
1235  ndim,
1236  dims,
1237  lbs,
1238  arg->u.array.elmbasetype,
1239  arg->u.array.elm->typlen,
1240  arg->u.array.elm->typbyval,
1241  arg->u.array.elm->typalign);
1242 
1243  return PointerGetDatum(array);
1244 }
static int32 next
Definition: blutils.c:213
#define MAXDIM
Definition: c.h:536
#define PointerGetDatum(X)
Definition: postgres.h:556
PLyObToArray array
Definition: plpy_typeio.h:142
#define ERROR
Definition: elog.h:43
#define PLy_elog
#define MaxAllocSize
Definition: memutils.h:40
uintptr_t Datum
Definition: postgres.h:367
PLyObToDatum * elm
Definition: plpy_typeio.h:101
void * palloc(Size size)
Definition: mcxt.c:949
int i
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3326
static void PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list, int *dims, int ndim, int dim, Datum *elems, bool *nulls, int *currelem)
Definition: plpy_typeio.c:1251
union PLyObToDatum::@166 u

◆ PLySequence_ToArray_recurse()

static void PLySequence_ToArray_recurse ( PLyObToDatum elm,
PyObject *  list,
int *  dims,
int  ndim,
int  dim,
Datum elems,
bool nulls,
int *  currelem 
)
static

Definition at line 1251 of file plpy_typeio.c.

References ereport, errdetail(), errmsg(), ERROR, PLyObToDatum::func, and i.

Referenced by PLySequence_ToArray().

1254 {
1255  int i;
1256 
1257  if (PySequence_Length(list) != dims[dim])
1258  ereport(ERROR,
1259  (errmsg("wrong length of inner sequence: has length %d, but %d was expected",
1260  (int) PySequence_Length(list), dims[dim]),
1261  (errdetail("To construct a multidimensional array, the inner sequences must all have the same length."))));
1262 
1263  if (dim < ndim - 1)
1264  {
1265  for (i = 0; i < dims[dim]; i++)
1266  {
1267  PyObject *sublist = PySequence_GetItem(list, i);
1268 
1269  PLySequence_ToArray_recurse(elm, sublist, dims, ndim, dim + 1,
1270  elems, nulls, currelem);
1271  Py_XDECREF(sublist);
1272  }
1273  }
1274  else
1275  {
1276  for (i = 0; i < dims[dim]; i++)
1277  {
1278  PyObject *obj = PySequence_GetItem(list, i);
1279 
1280  elems[*currelem] = elm->func(elm, obj, &nulls[*currelem], true);
1281  Py_XDECREF(obj);
1282  (*currelem)++;
1283  }
1284  }
1285 }
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
static void PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list, int *dims, int ndim, int dim, Datum *elems, bool *nulls, int *currelem)
Definition: plpy_typeio.c:1251

◆ PLySequence_ToComposite()

static Datum PLySequence_ToComposite ( PLyObToDatum arg,
TupleDesc  desc,
PyObject *  sequence 
)
static

Definition at line 1418 of file plpy_typeio.c.

References Assert, PLyObToTuple::atts, ereport, errcode(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, idx(), TupleDescData::natts, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyObToDatum::tuple, TupleDescAttr, PLyObToDatum::u, value, and values.

Referenced by PLyObject_ToComposite().

1419 {
1420  Datum result;
1421  HeapTuple tuple;
1422  Datum *values;
1423  bool *nulls;
1424  volatile int idx;
1425  volatile int i;
1426 
1427  Assert(PySequence_Check(sequence));
1428 
1429  /*
1430  * Check that sequence length is exactly same as PG tuple's. We actually
1431  * can ignore exceeding items or assume missing ones as null but to avoid
1432  * plpython developer's errors we are strict here
1433  */
1434  idx = 0;
1435  for (i = 0; i < desc->natts; i++)
1436  {
1437  if (!TupleDescAttr(desc, i)->attisdropped)
1438  idx++;
1439  }
1440  if (PySequence_Length(sequence) != idx)
1441  ereport(ERROR,
1442  (errcode(ERRCODE_DATATYPE_MISMATCH),
1443  errmsg("length of returned sequence did not match number of columns in row")));
1444 
1445  /* Build tuple */
1446  values = palloc(sizeof(Datum) * desc->natts);
1447  nulls = palloc(sizeof(bool) * desc->natts);
1448  idx = 0;
1449  for (i = 0; i < desc->natts; ++i)
1450  {
1451  PyObject *volatile value;
1452  PLyObToDatum *att;
1453 
1454  if (TupleDescAttr(desc, i)->attisdropped)
1455  {
1456  values[i] = (Datum) 0;
1457  nulls[i] = true;
1458  continue;
1459  }
1460 
1461  value = NULL;
1462  att = &arg->u.tuple.atts[i];
1463  PG_TRY();
1464  {
1465  value = PySequence_GetItem(sequence, idx);
1466  Assert(value);
1467 
1468  values[i] = att->func(att, value, &nulls[i], false);
1469 
1470  Py_XDECREF(value);
1471  value = NULL;
1472  }
1473  PG_CATCH();
1474  {
1475  Py_XDECREF(value);
1476  PG_RE_THROW();
1477  }
1478  PG_END_TRY();
1479 
1480  idx++;
1481  }
1482 
1483  tuple = heap_form_tuple(desc, values, nulls);
1484  result = heap_copy_tuple_as_datum(tuple, desc);
1485  heap_freetuple(tuple);
1486 
1487  pfree(values);
1488  pfree(nulls);
1489 
1490  return result;
1491 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @145 value
int errcode(int sqlerrcode)
Definition: elog.c:608
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:263
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
uintptr_t Datum
Definition: postgres.h:367
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
#define PG_RE_THROW()
Definition: elog.h:363
static Datum values[MAXATTR]
Definition: bootstrap.c:167
PLyObToTuple tuple
Definition: plpy_typeio.h:143
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
PLyObToDatum * atts
Definition: plpy_typeio.h:113
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347
union PLyObToDatum::@166 u

◆ PLyString_FromScalar()

static PyObject * PLyString_FromScalar ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 641 of file plpy_typeio.c.

References OutputFunctionCall(), pfree(), PLyDatumToOb::scalar, PLyScalarToOb::typfunc, and PLyDatumToOb::u.

Referenced by PLy_input_setup_func().

642 {
643  char *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
644  PyObject *r = PyString_FromString(x);
645 
646  pfree(x);
647  return r;
648 }
FmgrInfo typfunc
Definition: plpy_typeio.h:32
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1575
void pfree(void *pointer)
Definition: mcxt.c:1056
PLyScalarToOb scalar
Definition: plpy_typeio.h:68
union PLyDatumToOb::@165 u

◆ PLyString_ToComposite()

static Datum PLyString_ToComposite ( PLyObToDatum arg,
PyObject *  string,
bool  inarray 
)
static

Definition at line 1292 of file plpy_typeio.c.

References ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_oid, InputFunctionCall(), PLyObToDatum::mcxt, OidIsValid, PLyObject_AsString(), PLyObToTuple::recinfunc, generate_unaccent_rules::str, PLyObToDatum::tuple, PLyObToDatum::typmod, PLyObToDatum::typoid, and PLyObToDatum::u.

Referenced by PLyObject_ToComposite().

1293 {
1294  char *str;
1295 
1296  /*
1297  * Set up call data for record_in, if we didn't already. (We can't just
1298  * use DirectFunctionCall, because record_in needs a fn_extra field.)
1299  */
1300  if (!OidIsValid(arg->u.tuple.recinfunc.fn_oid))
1301  fmgr_info_cxt(F_RECORD_IN, &arg->u.tuple.recinfunc, arg->mcxt);
1302 
1303  str = PLyObject_AsString(string);
1304 
1305  /*
1306  * If we are parsing a composite type within an array, and the string
1307  * isn't a valid record literal, there's a high chance that the function
1308  * did something like:
1309  *
1310  * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
1311  * LANGUAGE plpython;
1312  *
1313  * Before PostgreSQL 10, that was interpreted as a single-dimensional
1314  * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
1315  * for multi-dimensional arrays, and it is now interpreted as a
1316  * two-dimensional array, containing two records, 'foo', and 'bar'.
1317  * record_in() will throw an error, because "foo" is not a valid record
1318  * literal.
1319  *
1320  * To make that less confusing to users who are upgrading from older
1321  * versions, try to give a hint in the typical instances of that. If we
1322  * are parsing an array of composite types, and we see a string literal
1323  * that is not a valid record literal, give a hint. We only want to give
1324  * the hint in the narrow case of a malformed string literal, not any
1325  * error from record_in(), so check for that case here specifically.
1326  *
1327  * This check better match the one in record_in(), so that we don't forbid
1328  * literals that are actually valid!
1329  */
1330  if (inarray)
1331  {
1332  char *ptr = str;
1333 
1334  /* Allow leading whitespace */
1335  while (*ptr && isspace((unsigned char) *ptr))
1336  ptr++;
1337  if (*ptr++ != '(')
1338  ereport(ERROR,
1339  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1340  errmsg("malformed record literal: \"%s\"", str),
1341  errdetail("Missing left parenthesis."),
1342  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".")));
1343  }
1344 
1345  return InputFunctionCall(&arg->u.tuple.recinfunc,
1346  str,
1347  arg->typoid,
1348  arg->typmod);
1349 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
int errcode(int sqlerrcode)
Definition: elog.c:608
#define OidIsValid(objectId)
Definition: c.h:645
#define ERROR
Definition: elog.h:43
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:1023
int errdetail(const char *fmt,...)
Definition: elog.c:955
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:134
#define ereport(elevel, rest)
Definition: elog.h:141
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1531
Oid fn_oid
Definition: fmgr.h:59
MemoryContext mcxt
Definition: plpy_typeio.h:138
PLyObToTuple tuple
Definition: plpy_typeio.h:143
int errmsg(const char *fmt,...)
Definition: elog.c:822
FmgrInfo recinfunc
Definition: plpy_typeio.h:116
union PLyObToDatum::@166 u