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 * PLyLong_FromInt16 (PLyDatumToOb *arg, Datum d)
 
static PyObject * PLyLong_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 * PLyUnicode_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 (PyObject *obj, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, PLyObToDatum *elm, Oid elmbasetype)
 
static Datum PLyUnicode_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 81 of file plpy_typeio.c.

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

References arg, MemoryContextReset(), MemoryContextSwitchTo(), PLy_current_execution_context(), PLy_get_scratch_context(), and val.

Referenced by PLy_function_build_args().

◆ PLy_input_from_tuple()

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

Definition at line 134 of file plpy_typeio.c.

135 {
136  PyObject *dict;
138  MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
139  MemoryContext oldcontext;
140 
141  /*
142  * As in PLy_input_convert, do the work in the scratch context.
143  */
144  MemoryContextReset(scratch_context);
145 
146  oldcontext = MemoryContextSwitchTo(scratch_context);
147 
148  dict = PLyDict_FromTuple(arg, tuple, desc, include_generated);
149 
150  MemoryContextSwitchTo(oldcontext);
151 
152  return dict;
153 }
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:815

References arg, 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().

◆ PLy_input_setup_func()

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

Definition at line 418 of file plpy_typeio.c.

421 {
422  TypeCacheEntry *typentry;
423  char typtype;
424  Oid trfuncid;
425  Oid typoutput;
426  bool typisvarlena;
427 
428  /* Since this is recursive, it could theoretically be driven to overflow */
430 
431  arg->typoid = typeOid;
432  arg->typmod = typmod;
433  arg->mcxt = arg_mcxt;
434 
435  /*
436  * Fetch typcache entry for the target type, asking for whatever info
437  * we'll need later. RECORD is a special case: just treat it as composite
438  * without bothering with the typcache entry.
439  */
440  if (typeOid != RECORDOID)
441  {
442  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
443  typtype = typentry->typtype;
444  arg->typbyval = typentry->typbyval;
445  arg->typlen = typentry->typlen;
446  arg->typalign = typentry->typalign;
447  }
448  else
449  {
450  typentry = NULL;
451  typtype = TYPTYPE_COMPOSITE;
452  /* hard-wired knowledge about type RECORD: */
453  arg->typbyval = false;
454  arg->typlen = -1;
455  arg->typalign = TYPALIGN_DOUBLE;
456  }
457 
458  /*
459  * Choose conversion method. Note that transform functions are checked
460  * for composite and scalar types, but not for arrays or domains. This is
461  * somewhat historical, but we'd have a problem allowing them on domains,
462  * since we drill down through all levels of a domain nest without looking
463  * at the intermediate levels at all.
464  */
465  if (typtype == TYPTYPE_DOMAIN)
466  {
467  /* Domain --- we don't care, just recurse down to the base type */
468  PLy_input_setup_func(arg, arg_mcxt,
469  typentry->domainBaseType,
470  typentry->domainBaseTypmod,
471  proc);
472  }
473  else if (typentry &&
474  IsTrueArrayType(typentry))
475  {
476  /* Standard array */
477  arg->func = PLyList_FromArray;
478  /* Recursively set up conversion info for the element type */
479  arg->u.array.elm = (PLyDatumToOb *)
480  MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb));
481  PLy_input_setup_func(arg->u.array.elm, arg_mcxt,
482  typentry->typelem, typmod,
483  proc);
484  }
485  else if ((trfuncid = get_transform_fromsql(typeOid,
486  proc->langid,
487  proc->trftypes)))
488  {
490  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
491  }
492  else if (typtype == TYPTYPE_COMPOSITE)
493  {
494  /* Named composite type, or RECORD */
495  arg->func = PLyDict_FromComposite;
496  /* We'll set up the per-field data later */
497  arg->u.tuple.recdesc = NULL;
498  arg->u.tuple.typentry = typentry;
499  arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
500  arg->u.tuple.atts = NULL;
501  arg->u.tuple.natts = 0;
502  }
503  else
504  {
505  /* Scalar type, but we have a couple of special cases */
506  switch (typeOid)
507  {
508  case BOOLOID:
509  arg->func = PLyBool_FromBool;
510  break;
511  case FLOAT4OID:
512  arg->func = PLyFloat_FromFloat4;
513  break;
514  case FLOAT8OID:
515  arg->func = PLyFloat_FromFloat8;
516  break;
517  case NUMERICOID:
518  arg->func = PLyDecimal_FromNumeric;
519  break;
520  case INT2OID:
521  arg->func = PLyLong_FromInt16;
522  break;
523  case INT4OID:
524  arg->func = PLyLong_FromInt32;
525  break;
526  case INT8OID:
527  arg->func = PLyLong_FromInt64;
528  break;
529  case OIDOID:
530  arg->func = PLyLong_FromOid;
531  break;
532  case BYTEAOID:
533  arg->func = PLyBytes_FromBytea;
534  break;
535  default:
536  arg->func = PLyUnicode_FromScalar;
537  getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
538  fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
539  break;
540  }
541  }
542 }
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:2120
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
static PyObject * PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:604
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:418
static PyObject * PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:616
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:781
static PyObject * PLyLong_FromInt32(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:610
static PyObject * PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:550
static PyObject * PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:642
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:655
static PyObject * PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:564
static PyObject * PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:558
static PyObject * PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:622
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:667
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:628
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:570
void check_stack_depth(void)
Definition: postgres.c:3564
unsigned int Oid
Definition: postgres_ext.h:31
int32 domainBaseTypmod
Definition: typcache.h:115
char typalign
Definition: typcache.h:41
char typtype
Definition: typcache.h:43
bool typbyval
Definition: typcache.h:40
int16 typlen
Definition: typcache.h:39
Oid domainBaseType
Definition: typcache.h:114
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:356
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:156
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:149

References arg, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, fmgr_info_cxt(), get_transform_fromsql(), getTypeOutputInfo(), INVALID_TUPLEDESC_IDENTIFIER, PLyProcedure::langid, lookup_type_cache(), MemoryContextAllocZero(), PLyBool_FromBool(), PLyBytes_FromBytea(), PLyDecimal_FromNumeric(), PLyDict_FromComposite(), PLyFloat_FromFloat4(), PLyFloat_FromFloat8(), PLyList_FromArray(), PLyLong_FromInt16(), PLyLong_FromInt32(), PLyLong_FromInt64(), PLyLong_FromOid(), PLyObject_FromTransform(), PLyUnicode_FromScalar(), PLyProcedure::trftypes, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TYPECACHE_DOMAIN_BASE_INFO, TypeCacheEntry::typelem, TypeCacheEntry::typlen, and TypeCacheEntry::typtype.

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

◆ PLy_input_setup_tuple()

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

Definition at line 165 of file plpy_typeio.c.

166 {
167  int i;
168 
169  /* We should be working on a previously-set-up struct */
170  Assert(arg->func == PLyDict_FromComposite);
171 
172  /* Save pointer to tupdesc, but only if this is an anonymous record type */
173  if (arg->typoid == RECORDOID && arg->typmod < 0)
174  arg->u.tuple.recdesc = desc;
175 
176  /* (Re)allocate atts array as needed */
177  if (arg->u.tuple.natts != desc->natts)
178  {
179  if (arg->u.tuple.atts)
180  pfree(arg->u.tuple.atts);
181  arg->u.tuple.natts = desc->natts;
182  arg->u.tuple.atts = (PLyDatumToOb *)
184  desc->natts * sizeof(PLyDatumToOb));
185  }
186 
187  /* Fill the atts entries, except for dropped columns */
188  for (i = 0; i < desc->natts; i++)
189  {
190  Form_pg_attribute attr = TupleDescAttr(desc, i);
191  PLyDatumToOb *att = &arg->u.tuple.atts[i];
192 
193  if (attr->attisdropped)
194  continue;
195 
196  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
197  continue; /* already set up this entry */
198 
199  PLy_input_setup_func(att, arg->mcxt,
200  attr->atttypid, attr->atttypmod,
201  proc);
202  }
203 }
#define Assert(condition)
Definition: c.h:861
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1521
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
int32 typmod
Definition: plpy_typeio.h:61
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References arg, Assert, i, MemoryContextAllocZero(), TupleDescData::natts, pfree(), PLy_input_setup_func(), PLyDict_FromComposite(), TupleDescAttr, PLyDatumToOb::typmod, and PLyDatumToOb::typoid.

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

◆ PLy_output_convert()

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

Definition at line 120 of file plpy_typeio.c.

121 {
122  /* at outer level, we are not considering an array element */
123  return arg->func(arg, val, isnull, false);
124 }

References arg, and val.

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

◆ PLy_output_setup_func()

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

Definition at line 296 of file plpy_typeio.c.

299 {
300  TypeCacheEntry *typentry;
301  char typtype;
302  Oid trfuncid;
303  Oid typinput;
304 
305  /* Since this is recursive, it could theoretically be driven to overflow */
307 
308  arg->typoid = typeOid;
309  arg->typmod = typmod;
310  arg->mcxt = arg_mcxt;
311 
312  /*
313  * Fetch typcache entry for the target type, asking for whatever info
314  * we'll need later. RECORD is a special case: just treat it as composite
315  * without bothering with the typcache entry.
316  */
317  if (typeOid != RECORDOID)
318  {
319  typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
320  typtype = typentry->typtype;
321  arg->typbyval = typentry->typbyval;
322  arg->typlen = typentry->typlen;
323  arg->typalign = typentry->typalign;
324  }
325  else
326  {
327  typentry = NULL;
328  typtype = TYPTYPE_COMPOSITE;
329  /* hard-wired knowledge about type RECORD: */
330  arg->typbyval = false;
331  arg->typlen = -1;
332  arg->typalign = TYPALIGN_DOUBLE;
333  }
334 
335  /*
336  * Choose conversion method. Note that transform functions are checked
337  * for composite and scalar types, but not for arrays or domains. This is
338  * somewhat historical, but we'd have a problem allowing them on domains,
339  * since we drill down through all levels of a domain nest without looking
340  * at the intermediate levels at all.
341  */
342  if (typtype == TYPTYPE_DOMAIN)
343  {
344  /* Domain */
345  arg->func = PLyObject_ToDomain;
346  arg->u.domain.domain_info = NULL;
347  /* Recursively set up conversion info for the element type */
348  arg->u.domain.base = (PLyObToDatum *)
349  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
350  PLy_output_setup_func(arg->u.domain.base, arg_mcxt,
351  typentry->domainBaseType,
352  typentry->domainBaseTypmod,
353  proc);
354  }
355  else if (typentry &&
356  IsTrueArrayType(typentry))
357  {
358  /* Standard array */
359  arg->func = PLySequence_ToArray;
360  /* Get base type OID to insert into constructed array */
361  /* (note this might not be the same as the immediate child type) */
362  arg->u.array.elmbasetype = getBaseType(typentry->typelem);
363  /* Recursively set up conversion info for the element type */
364  arg->u.array.elm = (PLyObToDatum *)
365  MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
366  PLy_output_setup_func(arg->u.array.elm, arg_mcxt,
367  typentry->typelem, typmod,
368  proc);
369  }
370  else if ((trfuncid = get_transform_tosql(typeOid,
371  proc->langid,
372  proc->trftypes)))
373  {
374  arg->func = PLyObject_ToTransform;
375  fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
376  }
377  else if (typtype == TYPTYPE_COMPOSITE)
378  {
379  /* Named composite type, or RECORD */
380  arg->func = PLyObject_ToComposite;
381  /* We'll set up the per-field data later */
382  arg->u.tuple.recdesc = NULL;
383  arg->u.tuple.typentry = typentry;
384  arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
385  arg->u.tuple.atts = NULL;
386  arg->u.tuple.natts = 0;
387  /* Mark this invalid till needed, too */
388  arg->u.tuple.recinfunc.fn_oid = InvalidOid;
389  }
390  else
391  {
392  /* Scalar type, but we have a couple of special cases */
393  switch (typeOid)
394  {
395  case BOOLOID:
396  arg->func = PLyObject_ToBool;
397  break;
398  case BYTEAOID:
399  arg->func = PLyObject_ToBytea;
400  break;
401  default:
402  arg->func = PLyObject_ToScalar;
403  getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam);
404  fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt);
405  break;
406  }
407  }
408 }
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:2142
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:296
static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:879
static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:897
static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1074
static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1116
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:941
static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1133
static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1099
#define InvalidOid
Definition: postgres_ext.h:36

References arg, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, fmgr_info_cxt(), get_transform_tosql(), getBaseType(), getTypeInputInfo(), INVALID_TUPLEDESC_IDENTIFIER, InvalidOid, PLyProcedure::langid, lookup_type_cache(), MemoryContextAllocZero(), PLyObject_ToBool(), PLyObject_ToBytea(), PLyObject_ToComposite(), PLyObject_ToDomain(), PLyObject_ToScalar(), PLyObject_ToTransform(), PLySequence_ToArray(), PLyProcedure::trftypes, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TYPECACHE_DOMAIN_BASE_INFO, TypeCacheEntry::typelem, TypeCacheEntry::typlen, and TypeCacheEntry::typtype.

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

◆ PLy_output_setup_record()

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

Definition at line 261 of file plpy_typeio.c.

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

References arg, Assert, BlessTupleDesc(), PLy_output_setup_tuple(), TupleDescData::tdtypeid, and TupleDescData::tdtypmod.

Referenced by PLy_exec_function().

◆ PLy_output_setup_tuple()

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

Definition at line 215 of file plpy_typeio.c.

216 {
217  int i;
218 
219  /* We should be working on a previously-set-up struct */
220  Assert(arg->func == PLyObject_ToComposite);
221 
222  /* Save pointer to tupdesc, but only if this is an anonymous record type */
223  if (arg->typoid == RECORDOID && arg->typmod < 0)
224  arg->u.tuple.recdesc = desc;
225 
226  /* (Re)allocate atts array as needed */
227  if (arg->u.tuple.natts != desc->natts)
228  {
229  if (arg->u.tuple.atts)
230  pfree(arg->u.tuple.atts);
231  arg->u.tuple.natts = desc->natts;
232  arg->u.tuple.atts = (PLyObToDatum *)
234  desc->natts * sizeof(PLyObToDatum));
235  }
236 
237  /* Fill the atts entries, except for dropped columns */
238  for (i = 0; i < desc->natts; i++)
239  {
240  Form_pg_attribute attr = TupleDescAttr(desc, i);
241  PLyObToDatum *att = &arg->u.tuple.atts[i];
242 
243  if (attr->attisdropped)
244  continue;
245 
246  if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
247  continue; /* already set up this entry */
248 
249  PLy_output_setup_func(att, arg->mcxt,
250  attr->atttypid, attr->atttypmod,
251  proc);
252  }
253 }

References arg, Assert, i, MemoryContextAllocZero(), TupleDescData::natts, pfree(), PLy_output_setup_func(), PLyObject_ToComposite(), TupleDescAttr, PLyObToDatum::typmod, and PLyObToDatum::typoid.

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

◆ PLyBool_FromBool()

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

Definition at line 550 of file plpy_typeio.c.

551 {
552  if (DatumGetBool(d))
553  Py_RETURN_TRUE;
554  Py_RETURN_FALSE;
555 }
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

References DatumGetBool().

Referenced by PLy_input_setup_func().

◆ PLyBytes_FromBytea()

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

Definition at line 628 of file plpy_typeio.c.

629 {
630  text *txt = DatumGetByteaPP(d);
631  char *str = VARDATA_ANY(txt);
632  size_t size = VARSIZE_ANY_EXHDR(txt);
633 
634  return PyBytes_FromStringAndSize(str, size);
635 }
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
const char * str
static pg_noinline void Size size
Definition: slab.c:607
Definition: c.h:690
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References DatumGetByteaPP, size, str, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by PLy_input_setup_func().

◆ PLyDecimal_FromNumeric()

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

Definition at line 570 of file plpy_typeio.c.

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

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

Referenced by PLy_input_setup_func().

◆ PLyDict_FromComposite()

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

Definition at line 781 of file plpy_typeio.c.

782 {
783  PyObject *dict;
784  HeapTupleHeader td;
785  Oid tupType;
786  int32 tupTypmod;
787  TupleDesc tupdesc;
788  HeapTupleData tmptup;
789 
790  td = DatumGetHeapTupleHeader(d);
791  /* Extract rowtype info and find a tupdesc */
792  tupType = HeapTupleHeaderGetTypeId(td);
793  tupTypmod = HeapTupleHeaderGetTypMod(td);
794  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
795 
796  /* Set up I/O funcs if not done yet */
797  PLy_input_setup_tuple(arg, tupdesc,
798  PLy_current_execution_context()->curr_proc);
799 
800  /* Build a temporary HeapTuple control structure */
802  tmptup.t_data = td;
803 
804  dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
805 
806  ReleaseTupleDesc(tupdesc);
807 
808  return dict;
809 }
signed int int32
Definition: c.h:497
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:466
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:456
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:165
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1850

References arg, 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().

◆ PLyDict_FromTuple()

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

Definition at line 815 of file plpy_typeio.c.

816 {
817  PyObject *volatile dict;
818 
819  /* Simple sanity check that desc matches */
820  Assert(desc->natts == arg->u.tuple.natts);
821 
822  dict = PyDict_New();
823  if (dict == NULL)
824  return NULL;
825 
826  PG_TRY();
827  {
828  int i;
829 
830  for (i = 0; i < arg->u.tuple.natts; i++)
831  {
832  PLyDatumToOb *att = &arg->u.tuple.atts[i];
833  Form_pg_attribute attr = TupleDescAttr(desc, i);
834  char *key;
835  Datum vattr;
836  bool is_null;
837  PyObject *value;
838 
839  if (attr->attisdropped)
840  continue;
841 
842  if (attr->attgenerated)
843  {
844  /* don't include unless requested */
845  if (!include_generated)
846  continue;
847  }
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 }
#define NameStr(name)
Definition: c.h:749
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
static struct @157 value
uintptr_t Datum
Definition: postgres.h:64
PLyDatumToObFunc func
Definition: plpy_typeio.h:59

References arg, Assert, PLyDatumToOb::func, heap_getattr(), i, sort-test::key, NameStr, TupleDescData::natts, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, TupleDescAttr, and value.

Referenced by PLy_input_from_tuple(), and PLyDict_FromComposite().

◆ PLyFloat_FromFloat4()

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

Definition at line 558 of file plpy_typeio.c.

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

References DatumGetFloat4().

Referenced by PLy_input_setup_func().

◆ PLyFloat_FromFloat8()

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

Definition at line 564 of file plpy_typeio.c.

565 {
566  return PyFloat_FromDouble(DatumGetFloat8(d));
567 }
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:494

References DatumGetFloat8().

Referenced by PLy_input_setup_func().

◆ PLyGenericObject_ToComposite()

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

Definition at line 1484 of file plpy_typeio.c.

1485 {
1486  Datum result;
1487  HeapTuple tuple;
1488  Datum *values;
1489  bool *nulls;
1490  volatile int i;
1491 
1492  /* Build tuple */
1493  values = palloc(sizeof(Datum) * desc->natts);
1494  nulls = palloc(sizeof(bool) * desc->natts);
1495  for (i = 0; i < desc->natts; ++i)
1496  {
1497  char *key;
1498  PyObject *volatile value;
1499  PLyObToDatum *att;
1500  Form_pg_attribute attr = TupleDescAttr(desc, i);
1501 
1502  if (attr->attisdropped)
1503  {
1504  values[i] = (Datum) 0;
1505  nulls[i] = true;
1506  continue;
1507  }
1508 
1509  key = NameStr(attr->attname);
1510  value = NULL;
1511  att = &arg->u.tuple.atts[i];
1512  PG_TRY();
1513  {
1514  value = PyObject_GetAttrString(object, key);
1515  if (!value)
1516  {
1517  /*
1518  * No attribute for this column in the object.
1519  *
1520  * If we are parsing a composite type in an array, a likely
1521  * cause is that the function contained something like "[[123,
1522  * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1523  * array, with a composite type (123, 'foo') in it. But now
1524  * it's interpreted as a two-dimensional array, and we try to
1525  * interpret "123" as the composite type. See also similar
1526  * heuristic in PLyObject_ToScalar().
1527  */
1528  ereport(ERROR,
1529  (errcode(ERRCODE_UNDEFINED_COLUMN),
1530  errmsg("attribute \"%s\" does not exist in Python object", key),
1531  inarray ?
1532  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".") :
1533  errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1534  }
1535 
1536  values[i] = att->func(att, value, &nulls[i], false);
1537 
1538  Py_XDECREF(value);
1539  value = NULL;
1540  }
1541  PG_CATCH();
1542  {
1543  Py_XDECREF(value);
1544  PG_RE_THROW();
1545  }
1546  PG_END_TRY();
1547  }
1548 
1549  tuple = heap_form_tuple(desc, values, nulls);
1550  result = heap_copy_tuple_as_datum(tuple, desc);
1551  heap_freetuple(tuple);
1552 
1553  pfree(values);
1554  pfree(nulls);
1555 
1556  return result;
1557 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:1080
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void * palloc(Size size)
Definition: mcxt.c:1317
PLyObToDatumFunc func
Definition: plpy_typeio.h:132

References arg, 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, TupleDescAttr, value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyList_FromArray()

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

Definition at line 667 of file plpy_typeio.c.

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

References arg, ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_NULLBITMAP, Assert, DatumGetArrayTypeP, MAXDIM, and PLyList_FromArray_recurse().

Referenced by PLy_input_setup_func().

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

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

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

◆ PLyLong_FromInt16()

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

Definition at line 604 of file plpy_typeio.c.

605 {
606  return PyLong_FromLong(DatumGetInt16(d));
607 }
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162

References DatumGetInt16().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromInt32()

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

Definition at line 610 of file plpy_typeio.c.

611 {
612  return PyLong_FromLong(DatumGetInt32(d));
613 }
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202

References DatumGetInt32().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromInt64()

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

Definition at line 616 of file plpy_typeio.c.

617 {
618  return PyLong_FromLongLong(DatumGetInt64(d));
619 }
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:385

References DatumGetInt64().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromOid()

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

Definition at line 622 of file plpy_typeio.c.

623 {
624  return PyLong_FromUnsignedLong(DatumGetObjectId(d));
625 }
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242

References DatumGetObjectId().

Referenced by PLy_input_setup_func().

◆ PLyMapping_ToComposite()

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

Definition at line 1342 of file plpy_typeio.c.

1343 {
1344  Datum result;
1345  HeapTuple tuple;
1346  Datum *values;
1347  bool *nulls;
1348  volatile int i;
1349 
1350  Assert(PyMapping_Check(mapping));
1351 
1352  /* Build tuple */
1353  values = palloc(sizeof(Datum) * desc->natts);
1354  nulls = palloc(sizeof(bool) * desc->natts);
1355  for (i = 0; i < desc->natts; ++i)
1356  {
1357  char *key;
1358  PyObject *volatile value;
1359  PLyObToDatum *att;
1360  Form_pg_attribute attr = TupleDescAttr(desc, i);
1361 
1362  if (attr->attisdropped)
1363  {
1364  values[i] = (Datum) 0;
1365  nulls[i] = true;
1366  continue;
1367  }
1368 
1369  key = NameStr(attr->attname);
1370  value = NULL;
1371  att = &arg->u.tuple.atts[i];
1372  PG_TRY();
1373  {
1374  value = PyMapping_GetItemString(mapping, key);
1375  if (!value)
1376  ereport(ERROR,
1377  (errcode(ERRCODE_UNDEFINED_COLUMN),
1378  errmsg("key \"%s\" not found in mapping", key),
1379  errhint("To return null in a column, "
1380  "add the value None to the mapping with the key named after the column.")));
1381 
1382  values[i] = att->func(att, value, &nulls[i], false);
1383 
1384  Py_XDECREF(value);
1385  value = NULL;
1386  }
1387  PG_CATCH();
1388  {
1389  Py_XDECREF(value);
1390  PG_RE_THROW();
1391  }
1392  PG_END_TRY();
1393  }
1394 
1395  tuple = heap_form_tuple(desc, values, nulls);
1396  result = heap_copy_tuple_as_datum(tuple, desc);
1397  heap_freetuple(tuple);
1398 
1399  pfree(values);
1400  pfree(nulls);
1401 
1402  return result;
1403 }

References arg, Assert, 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, TupleDescAttr, value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyObject_AsString()

char* PLyObject_AsString ( PyObject *  plrv)

Definition at line 1024 of file plpy_typeio.c.

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

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

Referenced by PLyObject_ToScalar(), and PLyUnicode_ToComposite().

◆ PLyObject_FromTransform()

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

Definition at line 655 of file plpy_typeio.c.

656 {
657  Datum t;
658 
659  t = FunctionCall1(&arg->u.transform.typtransform, d);
660  return (PyObject *) DatumGetPointer(t);
661 }
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:659
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312

References arg, DatumGetPointer(), and FunctionCall1.

Referenced by PLy_input_setup_func().

◆ PLyObject_ToBool()

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

Definition at line 879 of file plpy_typeio.c.

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 }
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102

References BoolGetDatum().

Referenced by PLy_output_setup_func().

◆ PLyObject_ToBytea()

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

Definition at line 897 of file plpy_typeio.c.

899 {
900  PyObject *volatile plrv_so = NULL;
901  Datum rv = (Datum) 0;
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_FINALLY();
926  {
927  Py_XDECREF(plrv_so);
928  }
929  PG_END_TRY();
930 
931  return rv;
932 }
#define VARHDRSZ
Definition: c.h:695
#define PG_FINALLY(...)
Definition: elog.h:388
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
#define VARDATA(PTR)
Definition: varatt.h:278
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References ERROR, len, palloc(), PG_END_TRY, PG_FINALLY, PG_TRY, PLy_elog, PointerGetDatum(), SET_VARSIZE, size, VARDATA, and VARHDRSZ.

Referenced by PLy_output_setup_func().

◆ PLyObject_ToComposite()

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

Definition at line 941 of file plpy_typeio.c.

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

References arg, Assert, lookup_rowtype_tupdesc(), TupleDescData::natts, PinTupleDesc, PLy_current_execution_context(), PLy_output_setup_tuple(), PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), PLySequence_ToComposite(), PLyUnicode_ToComposite(), and ReleaseTupleDesc.

Referenced by PLy_output_setup_func(), and PLy_output_setup_tuple().

◆ PLyObject_ToDomain()

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

Definition at line 1099 of file plpy_typeio.c.

1101 {
1102  Datum result;
1103  PLyObToDatum *base = arg->u.domain.base;
1104 
1105  result = base->func(base, plrv, isnull, inarray);
1106  domain_check(result, *isnull, arg->typoid,
1107  &arg->u.domain.domain_info, arg->mcxt);
1108  return result;
1109 }
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:346

References arg, domain_check(), and PLyObToDatum::func.

Referenced by PLy_output_setup_func().

◆ PLyObject_ToScalar()

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

Definition at line 1074 of file plpy_typeio.c.

1076 {
1077  char *str;
1078 
1079  if (plrv == Py_None)
1080  {
1081  *isnull = true;
1082  return (Datum) 0;
1083  }
1084  *isnull = false;
1085 
1086  str = PLyObject_AsString(plrv);
1087 
1088  return InputFunctionCall(&arg->u.scalar.typfunc,
1089  str,
1090  arg->u.scalar.typioparam,
1091  arg->typmod);
1092 }
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1530
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:1024

References arg, InputFunctionCall(), PLyObject_AsString(), and str.

Referenced by PLy_output_setup_func().

◆ PLyObject_ToTransform()

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

Definition at line 1116 of file plpy_typeio.c.

1118 {
1119  if (plrv == Py_None)
1120  {
1121  *isnull = true;
1122  return (Datum) 0;
1123  }
1124  *isnull = false;
1125  return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
1126 }

References arg, FunctionCall1, and PointerGetDatum().

Referenced by PLy_output_setup_func().

◆ PLySequence_ToArray()

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

Definition at line 1133 of file plpy_typeio.c.

1135 {
1136  ArrayBuildState *astate = NULL;
1137  int ndims = 1;
1138  int dims[MAXDIM];
1139  int lbs[MAXDIM];
1140 
1141  if (plrv == Py_None)
1142  {
1143  *isnull = true;
1144  return (Datum) 0;
1145  }
1146  *isnull = false;
1147 
1148  /*
1149  * For historical reasons, we allow any sequence (not only a list) at the
1150  * top level when converting a Python object to a SQL array. However, a
1151  * multi-dimensional array is recognized only when the object contains
1152  * true lists.
1153  */
1154  if (!PySequence_Check(plrv))
1155  ereport(ERROR,
1156  (errcode(ERRCODE_DATATYPE_MISMATCH),
1157  errmsg("return value of function with array return type is not a Python sequence")));
1158 
1159  /* Initialize dimensionality info with first-level dimension */
1160  memset(dims, 0, sizeof(dims));
1161  dims[0] = PySequence_Length(plrv);
1162 
1163  /*
1164  * Traverse the Python lists, in depth-first order, and collect all the
1165  * elements at the bottom level into an ArrayBuildState.
1166  */
1167  PLySequence_ToArray_recurse(plrv, &astate,
1168  &ndims, dims, 1,
1169  arg->u.array.elm,
1170  arg->u.array.elmbasetype);
1171 
1172  /* ensure we get zero-D array for no inputs, as per PG convention */
1173  if (astate == NULL)
1174  return PointerGetDatum(construct_empty_array(arg->u.array.elmbasetype));
1175 
1176  for (int i = 0; i < ndims; i++)
1177  lbs[i] = 1;
1178 
1179  return makeMdArrayResult(astate, ndims, dims, lbs,
1180  CurrentMemoryContext, true);
1181 }
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5440
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3568
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static void PLySequence_ToArray_recurse(PyObject *obj, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, PLyObToDatum *elm, Oid elmbasetype)
Definition: plpy_typeio.c:1193

References arg, construct_empty_array(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, i, makeMdArrayResult(), MAXDIM, PLySequence_ToArray_recurse(), and PointerGetDatum().

Referenced by PLy_output_setup_func().

◆ PLySequence_ToArray_recurse()

static void PLySequence_ToArray_recurse ( PyObject *  obj,
ArrayBuildState **  astatep,
int *  ndims,
int *  dims,
int  cur_depth,
PLyObToDatum elm,
Oid  elmbasetype 
)
static

Definition at line 1193 of file plpy_typeio.c.

1196 {
1197  int i;
1198  int len = PySequence_Length(obj);
1199 
1200  /* We should not get here with a non-sequence object */
1201  if (len < 0)
1202  PLy_elog(ERROR, "could not determine sequence length for function return value");
1203 
1204  for (i = 0; i < len; i++)
1205  {
1206  /* fetch the array element */
1207  PyObject *subobj = PySequence_GetItem(obj, i);
1208 
1209  /* need PG_TRY to ensure we release the subobj's refcount */
1210  PG_TRY();
1211  {
1212  /* multi-dimensional array? */
1213  if (PyList_Check(subobj))
1214  {
1215  /* set size when at first element in this level, else compare */
1216  if (i == 0 && *ndims == cur_depth)
1217  {
1218  /* array after some scalars at same level? */
1219  if (*astatep != NULL)
1220  ereport(ERROR,
1221  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1222  errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1223  /* too many dimensions? */
1224  if (cur_depth >= MAXDIM)
1225  ereport(ERROR,
1226  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1227  errmsg("number of array dimensions exceeds the maximum allowed (%d)",
1228  MAXDIM)));
1229  /* OK, add a dimension */
1230  dims[*ndims] = PySequence_Length(subobj);
1231  (*ndims)++;
1232  }
1233  else if (cur_depth >= *ndims ||
1234  PySequence_Length(subobj) != dims[cur_depth])
1235  ereport(ERROR,
1236  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1237  errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1238 
1239  /* recurse to fetch elements of this sub-array */
1240  PLySequence_ToArray_recurse(subobj, astatep,
1241  ndims, dims, cur_depth + 1,
1242  elm, elmbasetype);
1243  }
1244  else
1245  {
1246  Datum dat;
1247  bool isnull;
1248 
1249  /* scalar after some sub-arrays at same level? */
1250  if (*ndims != cur_depth)
1251  ereport(ERROR,
1252  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1253  errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1254 
1255  /* convert non-list object to Datum */
1256  dat = elm->func(elm, subobj, &isnull, true);
1257 
1258  /* create ArrayBuildState if we didn't already */
1259  if (*astatep == NULL)
1260  *astatep = initArrayResult(elmbasetype,
1261  CurrentMemoryContext, true);
1262 
1263  /* ... and save the element value in it */
1264  (void) accumArrayResult(*astatep, dat, isnull,
1265  elmbasetype, CurrentMemoryContext);
1266  }
1267  }
1268  PG_FINALLY();
1269  {
1270  Py_XDECREF(subobj);
1271  }
1272  PG_END_TRY();
1273  }
1274 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5338
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5281

References accumArrayResult(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, PLyObToDatum::func, i, initArrayResult(), len, MAXDIM, PG_END_TRY, PG_FINALLY, PG_TRY, and PLy_elog.

Referenced by PLySequence_ToArray().

◆ PLySequence_ToComposite()

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

Definition at line 1407 of file plpy_typeio.c.

1408 {
1409  Datum result;
1410  HeapTuple tuple;
1411  Datum *values;
1412  bool *nulls;
1413  volatile int idx;
1414  volatile int i;
1415 
1416  Assert(PySequence_Check(sequence));
1417 
1418  /*
1419  * Check that sequence length is exactly same as PG tuple's. We actually
1420  * can ignore exceeding items or assume missing ones as null but to avoid
1421  * plpython developer's errors we are strict here
1422  */
1423  idx = 0;
1424  for (i = 0; i < desc->natts; i++)
1425  {
1426  if (!TupleDescAttr(desc, i)->attisdropped)
1427  idx++;
1428  }
1429  if (PySequence_Length(sequence) != idx)
1430  ereport(ERROR,
1431  (errcode(ERRCODE_DATATYPE_MISMATCH),
1432  errmsg("length of returned sequence did not match number of columns in row")));
1433 
1434  /* Build tuple */
1435  values = palloc(sizeof(Datum) * desc->natts);
1436  nulls = palloc(sizeof(bool) * desc->natts);
1437  idx = 0;
1438  for (i = 0; i < desc->natts; ++i)
1439  {
1440  PyObject *volatile value;
1441  PLyObToDatum *att;
1442 
1443  if (TupleDescAttr(desc, i)->attisdropped)
1444  {
1445  values[i] = (Datum) 0;
1446  nulls[i] = true;
1447  continue;
1448  }
1449 
1450  value = NULL;
1451  att = &arg->u.tuple.atts[i];
1452  PG_TRY();
1453  {
1454  value = PySequence_GetItem(sequence, idx);
1455  Assert(value);
1456 
1457  values[i] = att->func(att, value, &nulls[i], false);
1458 
1459  Py_XDECREF(value);
1460  value = NULL;
1461  }
1462  PG_CATCH();
1463  {
1464  Py_XDECREF(value);
1465  PG_RE_THROW();
1466  }
1467  PG_END_TRY();
1468 
1469  idx++;
1470  }
1471 
1472  tuple = heap_form_tuple(desc, values, nulls);
1473  result = heap_copy_tuple_as_datum(tuple, desc);
1474  heap_freetuple(tuple);
1475 
1476  pfree(values);
1477  pfree(nulls);
1478 
1479  return result;
1480 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259

References arg, Assert, 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, TupleDescAttr, value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyUnicode_FromScalar()

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

Definition at line 642 of file plpy_typeio.c.

643 {
644  char *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
645  PyObject *r = PLyUnicode_FromString(x);
646 
647  pfree(x);
648  return r;
649 }
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
int x
Definition: isn.c:71
PyObject * PLyUnicode_FromString(const char *s)
Definition: plpy_util.c:118

References arg, OutputFunctionCall(), pfree(), PLyUnicode_FromString(), and x.

Referenced by PLy_input_setup_func().

◆ PLyUnicode_ToComposite()

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

Definition at line 1281 of file plpy_typeio.c.

1282 {
1283  char *str;
1284 
1285  /*
1286  * Set up call data for record_in, if we didn't already. (We can't just
1287  * use DirectFunctionCall, because record_in needs a fn_extra field.)
1288  */
1289  if (!OidIsValid(arg->u.tuple.recinfunc.fn_oid))
1290  fmgr_info_cxt(F_RECORD_IN, &arg->u.tuple.recinfunc, arg->mcxt);
1291 
1292  str = PLyObject_AsString(string);
1293 
1294  /*
1295  * If we are parsing a composite type within an array, and the string
1296  * isn't a valid record literal, there's a high chance that the function
1297  * did something like:
1298  *
1299  * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
1300  * LANGUAGE plpython;
1301  *
1302  * Before PostgreSQL 10, that was interpreted as a single-dimensional
1303  * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
1304  * for multi-dimensional arrays, and it is now interpreted as a
1305  * two-dimensional array, containing two records, 'foo', and 'bar'.
1306  * record_in() will throw an error, because "foo" is not a valid record
1307  * literal.
1308  *
1309  * To make that less confusing to users who are upgrading from older
1310  * versions, try to give a hint in the typical instances of that. If we
1311  * are parsing an array of composite types, and we see a string literal
1312  * that is not a valid record literal, give a hint. We only want to give
1313  * the hint in the narrow case of a malformed string literal, not any
1314  * error from record_in(), so check for that case here specifically.
1315  *
1316  * This check better match the one in record_in(), so that we don't forbid
1317  * literals that are actually valid!
1318  */
1319  if (inarray)
1320  {
1321  char *ptr = str;
1322 
1323  /* Allow leading whitespace */
1324  while (*ptr && isspace((unsigned char) *ptr))
1325  ptr++;
1326  if (*ptr++ != '(')
1327  ereport(ERROR,
1328  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1329  errmsg("malformed record literal: \"%s\"", str),
1330  errdetail("Missing left parenthesis."),
1331  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".")));
1332  }
1333 
1334  return InputFunctionCall(&arg->u.tuple.recinfunc,
1335  str,
1336  arg->typoid,
1337  arg->typmod);
1338 }
#define OidIsValid(objectId)
Definition: c.h:778
int errdetail(const char *fmt,...)
Definition: elog.c:1203

References arg, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, fmgr_info_cxt(), InputFunctionCall(), OidIsValid, PLyObject_AsString(), and str.

Referenced by PLyObject_ToComposite().