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 "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "plpython.h"
#include "plpy_typeio.h"
#include "plpy_elog.h"
#include "plpy_main.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)
 
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)
 
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 84 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().

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

◆ PLy_input_from_tuple()

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

Definition at line 137 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().

138 {
139  PyObject *dict;
141  MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
142  MemoryContext oldcontext;
143 
144  /*
145  * As in PLy_input_convert, do the work in the scratch context.
146  */
147  MemoryContextReset(scratch_context);
148 
149  oldcontext = MemoryContextSwitchTo(scratch_context);
150 
151  dict = PLyDict_FromTuple(arg, tuple, desc);
152 
153  MemoryContextSwitchTo(oldcontext);
154 
155  return dict;
156 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:134
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:822
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:418

◆ PLy_input_setup_func()

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

Definition at line 421 of file plpy_typeio.c.

References PLyDatumToOb::array, PLyTupleToOb::atts, BOOLOID, BYTEAOID, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, PLyArrayToOb::elm, FLOAT4OID, FLOAT8OID, fmgr_info_cxt(), PLyDatumToOb::func, get_transform_fromsql(), getTypeOutputInfo(), INT2OID, INT4OID, INT8OID, PLyProcedure::langid, lookup_type_cache(), PLyDatumToOb::mcxt, MemoryContextAllocZero(), PLyTupleToOb::natts, NUMERICOID, OidIsValid, OIDOID, 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, RECORDOID, PLyDatumToOb::scalar, PLyDatumToOb::transform, PLyProcedure::trftypes, PLyTupleToOb::tupdescseq, TypeCacheEntry::tupDescSeqNo, 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, TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, 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().

424 {
425  TypeCacheEntry *typentry;
426  char typtype;
427  Oid trfuncid;
428  Oid typoutput;
429  bool typisvarlena;
430 
431  /* Since this is recursive, it could theoretically be driven to overflow */
433 
434  arg->typoid = typeOid;
435  arg->typmod = typmod;
436  arg->mcxt = arg_mcxt;
437 
438  /*
439  * Fetch typcache entry for the target type, asking for whatever info
440  * we'll need later. RECORD is a special case: just treat it as composite
441  * without bothering with the typcache entry.
442  */
443  if (typeOid != RECORDOID)
444  {
445  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
446  typtype = typentry->typtype;
447  arg->typbyval = typentry->typbyval;
448  arg->typlen = typentry->typlen;
449  arg->typalign = typentry->typalign;
450  }
451  else
452  {
453  typentry = NULL;
454  typtype = TYPTYPE_COMPOSITE;
455  /* hard-wired knowledge about type RECORD: */
456  arg->typbyval = false;
457  arg->typlen = -1;
458  arg->typalign = 'd';
459  }
460 
461  /*
462  * Choose conversion method. Note that transform functions are checked
463  * for composite and scalar types, but not for arrays or domains. This is
464  * somewhat historical, but we'd have a problem allowing them on domains,
465  * since we drill down through all levels of a domain nest without looking
466  * at the intermediate levels at all.
467  */
468  if (typtype == TYPTYPE_DOMAIN)
469  {
470  /* Domain --- we don't care, just recurse down to the base type */
471  PLy_input_setup_func(arg, arg_mcxt,
472  typentry->domainBaseType,
473  typentry->domainBaseTypmod,
474  proc);
475  }
476  else if (typentry &&
477  OidIsValid(typentry->typelem) && typentry->typlen == -1)
478  {
479  /* Standard varlena array (cf. get_element_type) */
480  arg->func = PLyList_FromArray;
481  /* Recursively set up conversion info for the element type */
482  arg->u.array.elm = (PLyDatumToOb *)
483  MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb));
484  PLy_input_setup_func(arg->u.array.elm, arg_mcxt,
485  typentry->typelem, typmod,
486  proc);
487  }
488  else if ((trfuncid = get_transform_fromsql(typeOid,
489  proc->langid,
490  proc->trftypes)))
491  {
493  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
494  }
495  else if (typtype == TYPTYPE_COMPOSITE)
496  {
497  /* Named composite type, or RECORD */
499  /* We'll set up the per-field data later */
500  arg->u.tuple.recdesc = NULL;
501  arg->u.tuple.typentry = typentry;
502  arg->u.tuple.tupdescseq = typentry ? typentry->tupDescSeqNo - 1 : 0;
503  arg->u.tuple.atts = NULL;
504  arg->u.tuple.natts = 0;
505  }
506  else
507  {
508  /* Scalar type, but we have a couple of special cases */
509  switch (typeOid)
510  {
511  case BOOLOID:
512  arg->func = PLyBool_FromBool;
513  break;
514  case FLOAT4OID:
515  arg->func = PLyFloat_FromFloat4;
516  break;
517  case FLOAT8OID:
518  arg->func = PLyFloat_FromFloat8;
519  break;
520  case NUMERICOID:
522  break;
523  case INT2OID:
524  arg->func = PLyInt_FromInt16;
525  break;
526  case INT4OID:
527  arg->func = PLyInt_FromInt32;
528  break;
529  case INT8OID:
530  arg->func = PLyLong_FromInt64;
531  break;
532  case OIDOID:
533  arg->func = PLyLong_FromOid;
534  break;
535  case BYTEAOID:
536  arg->func = PLyBytes_FromBytea;
537  break;
538  default:
539  arg->func = PLyString_FromScalar;
540  getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
541  fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
542  break;
543  }
544  }
545 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1891
static PyObject * PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:619
TupleDesc recdesc
Definition: plpy_typeio.h:42
static PyObject * PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:613
PLyDatumToOb * atts
Definition: plpy_typeio.h:47
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2665
FmgrInfo typfunc
Definition: plpy_typeio.h:31
static PyObject * PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:553
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
#define OIDOID
Definition: pg_type.h:328
#define NUMERICOID
Definition: pg_type.h:554
#define INT4OID
Definition: pg_type.h:316
TypeCacheEntry * typentry
Definition: plpy_typeio.h:44
unsigned int Oid
Definition: postgres_ext.h:31
int16 typlen
Definition: typcache.h:37
#define OidIsValid(objectId)
Definition: c.h:586
bool typbyval
Definition: typcache.h:38
static PyObject * PLyString_FromScalar(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:649
FmgrInfo typtransform
Definition: plpy_typeio.h:53
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:788
Oid domainBaseType
Definition: typcache.h:101
static PyObject * PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:607
PLyArrayToOb array
Definition: plpy_typeio.h:68
union PLyDatumToOb::@150 u
static PyObject * PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:567
PLyDatumToObFunc func
Definition: plpy_typeio.h:58
PLyTransformToOb transform
Definition: plpy_typeio.h:70
#define INT2OID
Definition: pg_type.h:308
static PyObject * PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:561
int64 tupdescseq
Definition: plpy_typeio.h:45
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:635
void check_stack_depth(void)
Definition: postgres.c:3154
int32 typmod
Definition: plpy_typeio.h:60
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
int32 domainBaseTypmod
Definition: typcache.h:102
int16 typlen
Definition: plpy_typeio.h:62
#define RECORDOID
Definition: pg_type.h:680
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:573
PLyDatumToOb * elm
Definition: plpy_typeio.h:36
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:136
#define FLOAT4OID
Definition: pg_type.h:416
int64 tupDescSeqNo
Definition: typcache.h:83
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:311
#define INT8OID
Definition: pg_type.h:304
char typtype
Definition: typcache.h:41
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:674
static PyObject * PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:629
#define FLOAT8OID
Definition: pg_type.h:419
PLyScalarToOb scalar
Definition: plpy_typeio.h:67
#define BOOLOID
Definition: pg_type.h:288
#define BYTEAOID
Definition: pg_type.h:292
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:662
char typalign
Definition: typcache.h:39
MemoryContext mcxt
Definition: plpy_typeio.h:64
PLyTupleToOb tuple
Definition: plpy_typeio.h:69

◆ PLy_input_setup_tuple()

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

Definition at line 168 of file plpy_typeio.c.

References Assert, PLyTupleToOb::atts, PLyDatumToOb::func, i, PLyDatumToOb::mcxt, MemoryContextAllocZero(), PLyTupleToOb::natts, tupleDesc::natts, pfree(), PLy_input_setup_func(), PLyDict_FromComposite(), PLyTupleToOb::recdesc, RECORDOID, 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().

169 {
170  int i;
171 
172  /* We should be working on a previously-set-up struct */
174 
175  /* Save pointer to tupdesc, but only if this is an anonymous record type */
176  if (arg->typoid == RECORDOID && arg->typmod < 0)
177  arg->u.tuple.recdesc = desc;
178 
179  /* (Re)allocate atts array as needed */
180  if (arg->u.tuple.natts != desc->natts)
181  {
182  if (arg->u.tuple.atts)
183  pfree(arg->u.tuple.atts);
184  arg->u.tuple.natts = desc->natts;
185  arg->u.tuple.atts = (PLyDatumToOb *)
187  desc->natts * sizeof(PLyDatumToOb));
188  }
189 
190  /* Fill the atts entries, except for dropped columns */
191  for (i = 0; i < desc->natts; i++)
192  {
193  Form_pg_attribute attr = TupleDescAttr(desc, i);
194  PLyDatumToOb *att = &arg->u.tuple.atts[i];
195 
196  if (attr->attisdropped)
197  continue;
198 
199  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
200  continue; /* already set up this entry */
201 
202  PLy_input_setup_func(att, arg->mcxt,
203  attr->atttypid, attr->atttypmod,
204  proc);
205  }
206 }
TupleDesc recdesc
Definition: plpy_typeio.h:42
PLyDatumToOb * atts
Definition: plpy_typeio.h:47
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
int natts
Definition: tupdesc.h:79
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:788
union PLyDatumToOb::@150 u
void pfree(void *pointer)
Definition: mcxt.c:936
PLyDatumToObFunc func
Definition: plpy_typeio.h:58
int32 typmod
Definition: plpy_typeio.h:60
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define RECORDOID
Definition: pg_type.h:680
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
#define Assert(condition)
Definition: c.h:680
int i
MemoryContext mcxt
Definition: plpy_typeio.h:64
PLyTupleToOb tuple
Definition: plpy_typeio.h:69

◆ PLy_output_convert()

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

Definition at line 123 of file plpy_typeio.c.

References PLyObToDatum::func.

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

124 {
125  /* at outer level, we are not considering an array element */
126  return arg->func(arg, val, isnull, false);
127 }
PLyObToDatumFunc func
Definition: plpy_typeio.h:131
long val
Definition: informix.c:689

◆ PLy_output_setup_func()

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

Definition at line 299 of file plpy_typeio.c.

References PLyObToDatum::array, PLyObToTuple::atts, PLyObToDomain::base, BOOLOID, BYTEAOID, 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(), 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, RECORDOID, PLyObToDatum::scalar, PLyObToDatum::transform, PLyProcedure::trftypes, PLyObToTuple::tupdescseq, TypeCacheEntry::tupDescSeqNo, 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, TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, and PLyObToDatum::u.

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

302 {
303  TypeCacheEntry *typentry;
304  char typtype;
305  Oid trfuncid;
306  Oid typinput;
307 
308  /* Since this is recursive, it could theoretically be driven to overflow */
310 
311  arg->typoid = typeOid;
312  arg->typmod = typmod;
313  arg->mcxt = arg_mcxt;
314 
315  /*
316  * Fetch typcache entry for the target type, asking for whatever info
317  * we'll need later. RECORD is a special case: just treat it as composite
318  * without bothering with the typcache entry.
319  */
320  if (typeOid != RECORDOID)
321  {
322  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
323  typtype = typentry->typtype;
324  arg->typbyval = typentry->typbyval;
325  arg->typlen = typentry->typlen;
326  arg->typalign = typentry->typalign;
327  }
328  else
329  {
330  typentry = NULL;
331  typtype = TYPTYPE_COMPOSITE;
332  /* hard-wired knowledge about type RECORD: */
333  arg->typbyval = false;
334  arg->typlen = -1;
335  arg->typalign = 'd';
336  }
337 
338  /*
339  * Choose conversion method. Note that transform functions are checked
340  * for composite and scalar types, but not for arrays or domains. This is
341  * somewhat historical, but we'd have a problem allowing them on domains,
342  * since we drill down through all levels of a domain nest without looking
343  * at the intermediate levels at all.
344  */
345  if (typtype == TYPTYPE_DOMAIN)
346  {
347  /* Domain */
348  arg->func = PLyObject_ToDomain;
349  arg->u.domain.domain_info = NULL;
350  /* Recursively set up conversion info for the element type */
351  arg->u.domain.base = (PLyObToDatum *)
352  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
353  PLy_output_setup_func(arg->u.domain.base, arg_mcxt,
354  typentry->domainBaseType,
355  typentry->domainBaseTypmod,
356  proc);
357  }
358  else if (typentry &&
359  OidIsValid(typentry->typelem) && typentry->typlen == -1)
360  {
361  /* Standard varlena array (cf. get_element_type) */
362  arg->func = PLySequence_ToArray;
363  /* Get base type OID to insert into constructed array */
364  /* (note this might not be the same as the immediate child type) */
365  arg->u.array.elmbasetype = getBaseType(typentry->typelem);
366  /* Recursively set up conversion info for the element type */
367  arg->u.array.elm = (PLyObToDatum *)
368  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
369  PLy_output_setup_func(arg->u.array.elm, arg_mcxt,
370  typentry->typelem, typmod,
371  proc);
372  }
373  else if ((trfuncid = get_transform_tosql(typeOid,
374  proc->langid,
375  proc->trftypes)))
376  {
378  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
379  }
380  else if (typtype == TYPTYPE_COMPOSITE)
381  {
382  /* Named composite type, or RECORD */
384  /* We'll set up the per-field data later */
385  arg->u.tuple.recdesc = NULL;
386  arg->u.tuple.typentry = typentry;
387  arg->u.tuple.tupdescseq = typentry ? typentry->tupDescSeqNo - 1 : 0;
388  arg->u.tuple.atts = NULL;
389  arg->u.tuple.natts = 0;
390  /* Mark this invalid till needed, too */
392  }
393  else
394  {
395  /* Scalar type, but we have a couple of special cases */
396  switch (typeOid)
397  {
398  case BOOLOID:
399  arg->func = PLyObject_ToBool;
400  break;
401  case BYTEAOID:
402  arg->func = PLyObject_ToBytea;
403  break;
404  default:
405  arg->func = PLyObject_ToScalar;
406  getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam);
407  fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt);
408  break;
409  }
410  }
411 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
void * domain_info
Definition: plpy_typeio.h:121
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
union PLyObToDatum::@151 u
FmgrInfo typfunc
Definition: plpy_typeio.h:94
int64 tupdescseq
Definition: plpy_typeio.h:110
unsigned int Oid
Definition: postgres_ext.h:31
int16 typlen
Definition: typcache.h:37
#define OidIsValid(objectId)
Definition: c.h:586
bool typbyval
Definition: typcache.h:38
PLyObToTransform transform
Definition: plpy_typeio.h:144
PLyObToDatum * base
Definition: plpy_typeio.h:120
PLyObToDatumFunc func
Definition: plpy_typeio.h:131
PLyObToDomain domain
Definition: plpy_typeio.h:143
Oid domainBaseType
Definition: typcache.h:101
static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1085
PLyObToArray array
Definition: plpy_typeio.h:141
TupleDesc recdesc
Definition: plpy_typeio.h:107
PLyObToScalar scalar
Definition: plpy_typeio.h:140
void check_stack_depth(void)
Definition: postgres.c:3154
static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1110
static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:879
int32 domainBaseTypmod
Definition: typcache.h:102
FmgrInfo typtransform
Definition: plpy_typeio.h:126
#define RECORDOID
Definition: pg_type.h:680
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2632
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:944
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:136
TypeCacheEntry * typentry
Definition: plpy_typeio.h:109
int64 tupDescSeqNo
Definition: typcache.h:83
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:311
#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:100
MemoryContext mcxt
Definition: plpy_typeio.h:137
#define BOOLOID
Definition: pg_type.h:288
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1912
static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1127
#define BYTEAOID
Definition: pg_type.h:292
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:299
PLyObToTuple tuple
Definition: plpy_typeio.h:142
char typalign
Definition: typcache.h:39
static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1144
PLyObToDatum * atts
Definition: plpy_typeio.h:112
static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:897
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2290
FmgrInfo recinfunc
Definition: plpy_typeio.h:115

◆ PLy_output_setup_record()

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

Definition at line 264 of file plpy_typeio.c.

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

Referenced by PLy_function_build_args().

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

◆ PLy_output_setup_tuple()

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

Definition at line 218 of file plpy_typeio.c.

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

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

219 {
220  int i;
221 
222  /* We should be working on a previously-set-up struct */
224 
225  /* Save pointer to tupdesc, but only if this is an anonymous record type */
226  if (arg->typoid == RECORDOID && arg->typmod < 0)
227  arg->u.tuple.recdesc = desc;
228 
229  /* (Re)allocate atts array as needed */
230  if (arg->u.tuple.natts != desc->natts)
231  {
232  if (arg->u.tuple.atts)
233  pfree(arg->u.tuple.atts);
234  arg->u.tuple.natts = desc->natts;
235  arg->u.tuple.atts = (PLyObToDatum *)
237  desc->natts * sizeof(PLyObToDatum));
238  }
239 
240  /* Fill the atts entries, except for dropped columns */
241  for (i = 0; i < desc->natts; i++)
242  {
243  Form_pg_attribute attr = TupleDescAttr(desc, i);
244  PLyObToDatum *att = &arg->u.tuple.atts[i];
245 
246  if (attr->attisdropped)
247  continue;
248 
249  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
250  continue; /* already set up this entry */
251 
252  PLy_output_setup_func(att, arg->mcxt,
253  attr->atttypid, attr->atttypmod,
254  proc);
255  }
256 }
union PLyObToDatum::@151 u
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
int natts
Definition: tupdesc.h:79
PLyObToDatumFunc func
Definition: plpy_typeio.h:131
void pfree(void *pointer)
Definition: mcxt.c:936
TupleDesc recdesc
Definition: plpy_typeio.h:107
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define RECORDOID
Definition: pg_type.h:680
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:944
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
#define Assert(condition)
Definition: c.h:680
MemoryContext mcxt
Definition: plpy_typeio.h:137
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:299
PLyObToTuple tuple
Definition: plpy_typeio.h:142
int i
PLyObToDatum * atts
Definition: plpy_typeio.h:112

◆ PLyBool_FromBool()

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

Definition at line 553 of file plpy_typeio.c.

References DatumGetBool.

Referenced by PLy_input_setup_func().

554 {
555  if (DatumGetBool(d))
556  Py_RETURN_TRUE;
557  Py_RETURN_FALSE;
558 }
#define DatumGetBool(X)
Definition: postgres.h:399

◆ PLyBytes_FromBytea()

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

Definition at line 635 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().

636 {
637  text *txt = DatumGetByteaPP(d);
638  char *str = VARDATA_ANY(txt);
639  size_t size = VARSIZE_ANY_EXHDR(txt);
640 
641  return PyBytes_FromStringAndSize(str, size);
642 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
#define PyBytes_FromStringAndSize
Definition: plpython.h:85
#define DatumGetByteaPP(X)
Definition: fmgr.h:255
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
Definition: c.h:497

◆ PLyDecimal_FromNumeric()

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

Definition at line 573 of file plpy_typeio.c.

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

Referenced by PLy_input_setup_func().

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

◆ PLyDict_FromComposite()

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

Definition at line 788 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().

789 {
790  PyObject *dict;
791  HeapTupleHeader td;
792  Oid tupType;
793  int32 tupTypmod;
794  TupleDesc tupdesc;
795  HeapTupleData tmptup;
796 
797  td = DatumGetHeapTupleHeader(d);
798  /* Extract rowtype info and find a tupdesc */
799  tupType = HeapTupleHeaderGetTypeId(td);
800  tupTypmod = HeapTupleHeaderGetTypMod(td);
801  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
802 
803  /* Set up I/O funcs if not done yet */
804  PLy_input_setup_tuple(arg, tupdesc,
805  PLy_current_execution_context()->curr_proc);
806 
807  /* Build a temporary HeapTuple control structure */
809  tmptup.t_data = td;
810 
811  dict = PLyDict_FromTuple(arg, &tmptup, tupdesc);
812 
813  ReleaseTupleDesc(tupdesc);
814 
815  return dict;
816 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1618
unsigned int Oid
Definition: postgres_ext.h:31
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:259
signed int int32
Definition: c.h:294
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:460
uint32 t_len
Definition: htup.h:64
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:168
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:450
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:121
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:822
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:444

◆ PLyDict_FromTuple()

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

Definition at line 822 of file plpy_typeio.c.

References Assert, PLyTupleToOb::atts, PLyDatumToOb::func, heap_getattr, i, NameStr, PLyTupleToOb::natts, tupleDesc::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().

823 {
824  PyObject *volatile dict;
825 
826  /* Simple sanity check that desc matches */
827  Assert(desc->natts == arg->u.tuple.natts);
828 
829  dict = PyDict_New();
830  if (dict == NULL)
831  return NULL;
832 
833  PG_TRY();
834  {
835  int i;
836 
837  for (i = 0; i < arg->u.tuple.natts; i++)
838  {
839  PLyDatumToOb *att = &arg->u.tuple.atts[i];
840  Form_pg_attribute attr = TupleDescAttr(desc, i);
841  char *key;
842  Datum vattr;
843  bool is_null;
844  PyObject *value;
845 
846  if (attr->attisdropped)
847  continue;
848 
849  key = NameStr(attr->attname);
850  vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
851 
852  if (is_null)
853  PyDict_SetItemString(dict, key, Py_None);
854  else
855  {
856  value = att->func(att, vattr);
857  PyDict_SetItemString(dict, key, value);
858  Py_DECREF(value);
859  }
860  }
861  }
862  PG_CATCH();
863  {
864  Py_DECREF(dict);
865  PG_RE_THROW();
866  }
867  PG_END_TRY();
868 
869  return dict;
870 }
PLyDatumToOb * atts
Definition: plpy_typeio.h:47
static struct @130 value
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
int natts
Definition: tupdesc.h:79
union PLyDatumToOb::@150 u
PLyDatumToObFunc func
Definition: plpy_typeio.h:58
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:774
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:680
#define PG_RE_THROW()
Definition: elog.h:314
int i
#define NameStr(name)
Definition: c.h:557
#define PG_TRY()
Definition: elog.h:284
PLyTupleToOb tuple
Definition: plpy_typeio.h:69
#define PG_END_TRY()
Definition: elog.h:300

◆ PLyFloat_FromFloat4()

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

Definition at line 561 of file plpy_typeio.c.

References DatumGetFloat4.

Referenced by PLy_input_setup_func().

562 {
563  return PyFloat_FromDouble(DatumGetFloat4(d));
564 }
#define DatumGetFloat4(X)
Definition: postgres.h:686

◆ PLyFloat_FromFloat8()

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

Definition at line 567 of file plpy_typeio.c.

References DatumGetFloat8.

Referenced by PLy_input_setup_func().

568 {
569  return PyFloat_FromDouble(DatumGetFloat8(d));
570 }
#define DatumGetFloat8(X)
Definition: postgres.h:734

◆ PLyGenericObject_ToComposite()

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

Definition at line 1499 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, NameStr, tupleDesc::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().

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

◆ PLyInt_FromInt16()

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

Definition at line 607 of file plpy_typeio.c.

References DatumGetInt16.

Referenced by PLy_input_setup_func().

608 {
609  return PyInt_FromLong(DatumGetInt16(d));
610 }
#define DatumGetInt16(X)
Definition: postgres.h:450

◆ PLyInt_FromInt32()

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

Definition at line 613 of file plpy_typeio.c.

References DatumGetInt32.

Referenced by PLy_input_setup_func().

614 {
615  return PyInt_FromLong(DatumGetInt32(d));
616 }
#define DatumGetInt32(X)
Definition: postgres.h:478

◆ PLyList_FromArray()

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

Definition at line 674 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().

675 {
676  ArrayType *array = DatumGetArrayTypeP(d);
677  PLyDatumToOb *elm = arg->u.array.elm;
678  int ndim;
679  int *dims;
680  char *dataptr;
681  bits8 *bitmap;
682  int bitmask;
683 
684  if (ARR_NDIM(array) == 0)
685  return PyList_New(0);
686 
687  /* Array dimensions and left bounds */
688  ndim = ARR_NDIM(array);
689  dims = ARR_DIMS(array);
690  Assert(ndim < MAXDIM);
691 
692  /*
693  * We iterate the SQL array in the physical order it's stored in the
694  * datum. For example, for a 3-dimensional array the order of iteration
695  * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0]
696  * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till
697  * [1,m,k], and so on.
698  *
699  * In Python, there are no multi-dimensional lists as such, but they are
700  * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
701  * list of n m-element arrays, each element of which is k-element array.
702  * PLyList_FromArray_recurse() builds the Python list for a single
703  * dimension, and recurses for the next inner dimension.
704  */
705  dataptr = ARR_DATA_PTR(array);
706  bitmap = ARR_NULLBITMAP(array);
707  bitmask = 1;
708 
709  return PLyList_FromArray_recurse(elm, dims, ndim, 0,
710  &dataptr, &bitmap, &bitmask);
711 }
#define MAXDIM
Definition: c.h:477
PLyArrayToOb array
Definition: plpy_typeio.h:68
union PLyDatumToOb::@150 u
#define ARR_DIMS(a)
Definition: array.h:279
#define ARR_DATA_PTR(a)
Definition: array.h:307
PLyDatumToOb * elm
Definition: plpy_typeio.h:36
uint8 bits8
Definition: c.h:313
#define Assert(condition)
Definition: c.h:680
#define ARR_NDIM(a)
Definition: array.h:275
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:714
#define ARR_NULLBITMAP(a)
Definition: array.h:285
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ 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 714 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().

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

◆ PLyLong_FromInt64()

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

Definition at line 619 of file plpy_typeio.c.

References DatumGetInt64.

Referenced by PLy_input_setup_func().

620 {
621  /* on 32 bit platforms "long" may be too small */
622  if (sizeof(int64) > sizeof(long))
623  return PyLong_FromLongLong(DatumGetInt64(d));
624  else
625  return PyLong_FromLong(DatumGetInt64(d));
626 }
#define DatumGetInt64(X)
Definition: postgres.h:613

◆ PLyLong_FromOid()

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

Definition at line 629 of file plpy_typeio.c.

References DatumGetObjectId.

Referenced by PLy_input_setup_func().

630 {
631  return PyLong_FromUnsignedLong(DatumGetObjectId(d));
632 }
#define DatumGetObjectId(X)
Definition: postgres.h:506

◆ PLyMapping_ToComposite()

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

Definition at line 1357 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, NameStr, tupleDesc::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().

1358 {
1359  Datum result;
1360  HeapTuple tuple;
1361  Datum *values;
1362  bool *nulls;
1363  volatile int i;
1364 
1365  Assert(PyMapping_Check(mapping));
1366 
1367  /* Build tuple */
1368  values = palloc(sizeof(Datum) * desc->natts);
1369  nulls = palloc(sizeof(bool) * desc->natts);
1370  for (i = 0; i < desc->natts; ++i)
1371  {
1372  char *key;
1373  PyObject *volatile value;
1374  PLyObToDatum *att;
1375  Form_pg_attribute attr = TupleDescAttr(desc, i);
1376 
1377  if (attr->attisdropped)
1378  {
1379  values[i] = (Datum) 0;
1380  nulls[i] = true;
1381  continue;
1382  }
1383 
1384  key = NameStr(attr->attname);
1385  value = NULL;
1386  att = &arg->u.tuple.atts[i];
1387  PG_TRY();
1388  {
1389  value = PyMapping_GetItemString(mapping, key);
1390  if (!value)
1391  ereport(ERROR,
1392  (errcode(ERRCODE_UNDEFINED_COLUMN),
1393  errmsg("key \"%s\" not found in mapping", key),
1394  errhint("To return null in a column, "
1395  "add the value None to the mapping with the key named after the column.")));
1396 
1397  values[i] = att->func(att, value, &nulls[i], false);
1398 
1399  Py_XDECREF(value);
1400  value = NULL;
1401  }
1402  PG_CATCH();
1403  {
1404  Py_XDECREF(value);
1405  PG_RE_THROW();
1406  }
1407  PG_END_TRY();
1408  }
1409 
1410  tuple = heap_form_tuple(desc, values, nulls);
1411  result = heap_copy_tuple_as_datum(tuple, desc);
1412  heap_freetuple(tuple);
1413 
1414  pfree(values);
1415  pfree(nulls);
1416 
1417  return result;
1418 }
int errhint(const char *fmt,...)
Definition: elog.c:987
static struct @130 value
union PLyObToDatum::@151 u
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
int natts
Definition: tupdesc.h:79
PLyObToDatumFunc func
Definition: plpy_typeio.h:131
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:659
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:680
#define PG_RE_THROW()
Definition: elog.h:314
static Datum values[MAXATTR]
Definition: bootstrap.c:164
PLyObToTuple tuple
Definition: plpy_typeio.h:142
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:557
PLyObToDatum * atts
Definition: plpy_typeio.h:112
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLyObject_AsString()

char* PLyObject_AsString ( PyObject *  plrv)

Definition at line 1027 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().

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

◆ PLyObject_FromTransform()

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

Definition at line 662 of file plpy_typeio.c.

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

Referenced by PLy_input_setup_func().

663 {
664  Datum t;
665 
666  t = FunctionCall1(&arg->u.transform.typtransform, d);
667  return (PyObject *) DatumGetPointer(t);
668 }
FmgrInfo typtransform
Definition: plpy_typeio.h:53
union PLyDatumToOb::@150 u
PLyTransformToOb transform
Definition: plpy_typeio.h:70
uintptr_t Datum
Definition: postgres.h:372
#define DatumGetPointer(X)
Definition: postgres.h:555
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:603

◆ PLyObject_ToBool()

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

Definition at line 879 of file plpy_typeio.c.

References BoolGetDatum.

Referenced by PLy_output_setup_func().

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

◆ PLyObject_ToBytea()

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

Definition at line 897 of file plpy_typeio.c.

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

Referenced by PLy_output_setup_func().

899 {
900  PyObject *volatile plrv_so = NULL;
901  Datum rv;
902 
903  if (plrv == Py_None)
904  {
905  *isnull = true;
906  return (Datum) 0;
907  }
908  *isnull = false;
909 
910  plrv_so = PyObject_Bytes(plrv);
911  if (!plrv_so)
912  PLy_elog(ERROR, "could not create bytes representation of Python object");
913 
914  PG_TRY();
915  {
916  char *plrv_sc = PyBytes_AsString(plrv_so);
917  size_t len = PyBytes_Size(plrv_so);
918  size_t size = len + VARHDRSZ;
919  bytea *result = palloc(size);
920 
921  SET_VARSIZE(result, size);
922  memcpy(VARDATA(result), plrv_sc, len);
923  rv = PointerGetDatum(result);
924  }
925  PG_CATCH();
926  {
927  Py_XDECREF(plrv_so);
928  PG_RE_THROW();
929  }
930  PG_END_TRY();
931 
932  Py_XDECREF(plrv_so);
933 
934  return rv;
935 }
#define VARDATA(PTR)
Definition: postgres.h:303
#define PyObject_Bytes
Definition: plpython.h:87
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:503
#define PyBytes_AsString
Definition: plpython.h:84
#define ERROR
Definition: elog.h:43
#define PyBytes_Size
Definition: plpython.h:86
#define PLy_elog
Definition: plpy_elog.h:36
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
void * palloc(Size size)
Definition: mcxt.c:835
Definition: c.h:497
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLyObject_ToComposite()

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

Definition at line 944 of file plpy_typeio.c.

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

Referenced by PLy_output_setup_func(), and PLy_output_setup_tuple().

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

◆ PLyObject_ToDomain()

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

Definition at line 1110 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().

1112 {
1113  Datum result;
1114  PLyObToDatum *base = arg->u.domain.base;
1115 
1116  result = base->func(base, plrv, isnull, inarray);
1117  domain_check(result, *isnull, arg->typoid,
1118  &arg->u.domain.domain_info, arg->mcxt);
1119  return result;
1120 }
void * domain_info
Definition: plpy_typeio.h:121
union PLyObToDatum::@151 u
PLyObToDatum * base
Definition: plpy_typeio.h:120
PLyObToDatumFunc func
Definition: plpy_typeio.h:131
PLyObToDomain domain
Definition: plpy_typeio.h:143
uintptr_t Datum
Definition: postgres.h:372
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:327
MemoryContext mcxt
Definition: plpy_typeio.h:137

◆ PLyObject_ToScalar()

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

Definition at line 1085 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().

1087 {
1088  char *str;
1089 
1090  if (plrv == Py_None)
1091  {
1092  *isnull = true;
1093  return (Datum) 0;
1094  }
1095  *isnull = false;
1096 
1097  str = PLyObject_AsString(plrv);
1098 
1099  return InputFunctionCall(&arg->u.scalar.typfunc,
1100  str,
1101  arg->u.scalar.typioparam,
1102  arg->typmod);
1103 }
union PLyObToDatum::@151 u
FmgrInfo typfunc
Definition: plpy_typeio.h:94
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:1027
PLyObToScalar scalar
Definition: plpy_typeio.h:140
uintptr_t Datum
Definition: postgres.h:372
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1618

◆ PLyObject_ToTransform()

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

Definition at line 1127 of file plpy_typeio.c.

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

Referenced by PLy_output_setup_func().

1129 {
1130  if (plrv == Py_None)
1131  {
1132  *isnull = true;
1133  return (Datum) 0;
1134  }
1135  *isnull = false;
1136  return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
1137 }
union PLyObToDatum::@151 u
#define PointerGetDatum(X)
Definition: postgres.h:562
PLyObToTransform transform
Definition: plpy_typeio.h:144
FmgrInfo typtransform
Definition: plpy_typeio.h:126
uintptr_t Datum
Definition: postgres.h:372
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:603

◆ PLySequence_ToArray()

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

Definition at line 1144 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().

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

◆ 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 1255 of file plpy_typeio.c.

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

Referenced by PLySequence_ToArray().

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

◆ PLySequence_ToComposite()

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

Definition at line 1422 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(), tupleDesc::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().

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

◆ PLyString_FromScalar()

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

Definition at line 649 of file plpy_typeio.c.

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

Referenced by PLy_input_setup_func().

650 {
651  char *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
652  PyObject *r = PyString_FromString(x);
653 
654  pfree(x);
655  return r;
656 }
FmgrInfo typfunc
Definition: plpy_typeio.h:31
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1662
union PLyDatumToOb::@150 u
void pfree(void *pointer)
Definition: mcxt.c:936
PLyScalarToOb scalar
Definition: plpy_typeio.h:67

◆ PLyString_ToComposite()

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

Definition at line 1296 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().

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