PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plpy_typeio.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/transam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "parser/parse_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/numeric.h"
#include "utils/syscache.h"
#include "utils/typcache.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 void PLy_input_datum_func2 (PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
 
static void PLy_output_datum_func2 (PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
 
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_FromDatum (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 Datum PLyObject_ToBool (PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
 
static Datum PLyObject_ToBytea (PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
 
static Datum PLyObject_ToComposite (PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
 
static Datum PLyObject_ToDatum (PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
 
static Datum PLyObject_ToTransform (PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
 
static Datum PLySequence_ToArray (PLyObToDatum *arg, int32 typmod, PyObject *plrv, 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 (PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray)
 
static Datum PLyMapping_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
 
static Datum PLySequence_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
 
static Datum PLyGenericObject_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray)
 
void PLy_typeinfo_init (PLyTypeInfo *arg, MemoryContext mcxt)
 
void PLy_input_datum_func (PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
 
void PLy_output_datum_func (PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trftypes)
 
void PLy_input_tuple_funcs (PLyTypeInfo *arg, TupleDesc desc)
 
void PLy_output_tuple_funcs (PLyTypeInfo *arg, TupleDesc desc)
 
void PLy_output_record_funcs (PLyTypeInfo *arg, TupleDesc desc)
 
PyObject * PLyDict_FromTuple (PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
 
Datum PLyObject_ToCompositeDatum (PLyTypeInfo *info, TupleDesc desc, PyObject *plrv, bool inarray)
 
char * PLyObject_AsString (PyObject *plrv)
 

Function Documentation

void PLy_input_datum_func ( PLyTypeInfo arg,
Oid  typeOid,
HeapTuple  typeTup,
Oid  langid,
List trftypes 
)

Definition at line 87 of file plpy_typeio.c.

References PLyTypeInput::d, elog, ERROR, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, PLyTypeInfo::mcxt, and PLy_input_datum_func2().

Referenced by PLy_procedure_create().

88 {
89  if (arg->is_rowtype > 0)
90  elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
91  arg->is_rowtype = 0;
92  PLy_input_datum_func2(&(arg->in.d), arg->mcxt, typeOid, typeTup, langid, trftypes);
93 }
static void PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:437
PLyTypeInput in
Definition: plpy_typeio.h:86
#define ERROR
Definition: elog.h:43
MemoryContext mcxt
Definition: plpy_typeio.h:100
int is_rowtype
Definition: plpy_typeio.h:93
#define elog
Definition: elog.h:219
PLyDatumToOb d
Definition: plpy_typeio.h:41
static void PLy_input_datum_func2 ( PLyDatumToOb arg,
MemoryContext  arg_mcxt,
Oid  typeOid,
HeapTuple  typeTup,
Oid  langid,
List trftypes 
)
static

Definition at line 437 of file plpy_typeio.c.

References BOOLOID, BYTEAOID, PLyDatumToOb::elm, FLOAT4OID, FLOAT8OID, fmgr_info_cxt(), PLyDatumToOb::func, get_base_element_type(), get_transform_fromsql(), get_type_io_data(), getBaseType(), GETSTRUCT, getTypeIOParam(), HeapTupleGetOid, INT2OID, INT4OID, INT8OID, IOFunc_output, MemoryContextSwitchTo(), NUMERICOID, OIDOID, palloc0(), PLyBool_FromBool(), PLyBytes_FromBytea(), PLyDecimal_FromNumeric(), PLyFloat_FromFloat4(), PLyFloat_FromFloat8(), PLyInt_FromInt16(), PLyInt_FromInt32(), PLyList_FromArray(), PLyLong_FromInt64(), PLyLong_FromOid(), PLyObject_FromTransform(), PLyString_FromDatum(), PLyDatumToOb::typalign, PLyDatumToOb::typbyval, PLyDatumToOb::typfunc, PLyDatumToOb::typioparam, PLyDatumToOb::typlen, PLyDatumToOb::typmod, PLyDatumToOb::typoid, and PLyDatumToOb::typtransform.

Referenced by PLy_input_datum_func(), and PLy_input_tuple_funcs().

438 {
439  Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
440  Oid element_type;
441  Oid base_type;
442  Oid funcid;
443  MemoryContext oldcxt;
444 
445  oldcxt = MemoryContextSwitchTo(arg_mcxt);
446 
447  /* Get the type's conversion information */
448  fmgr_info_cxt(typeStruct->typoutput, &arg->typfunc, arg_mcxt);
449  arg->typoid = HeapTupleGetOid(typeTup);
450  arg->typmod = -1;
451  arg->typioparam = getTypeIOParam(typeTup);
452  arg->typbyval = typeStruct->typbyval;
453  arg->typlen = typeStruct->typlen;
454  arg->typalign = typeStruct->typalign;
455 
456  /* Determine which kind of Python object we will convert to */
457 
458  element_type = get_base_element_type(typeOid);
459  base_type = getBaseType(element_type ? element_type : typeOid);
460 
461  if ((funcid = get_transform_fromsql(base_type, langid, trftypes)))
462  {
464  fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
465  }
466  else
467  switch (base_type)
468  {
469  case BOOLOID:
470  arg->func = PLyBool_FromBool;
471  break;
472  case FLOAT4OID:
473  arg->func = PLyFloat_FromFloat4;
474  break;
475  case FLOAT8OID:
476  arg->func = PLyFloat_FromFloat8;
477  break;
478  case NUMERICOID:
480  break;
481  case INT2OID:
482  arg->func = PLyInt_FromInt16;
483  break;
484  case INT4OID:
485  arg->func = PLyInt_FromInt32;
486  break;
487  case INT8OID:
488  arg->func = PLyLong_FromInt64;
489  break;
490  case OIDOID:
491  arg->func = PLyLong_FromOid;
492  break;
493  case BYTEAOID:
494  arg->func = PLyBytes_FromBytea;
495  break;
496  default:
497  arg->func = PLyString_FromDatum;
498  break;
499  }
500 
501  if (element_type)
502  {
503  char dummy_delim;
504  Oid funcid;
505 
506  arg->elm = palloc0(sizeof(*arg->elm));
507  arg->elm->func = arg->func;
508  arg->elm->typtransform = arg->typtransform;
509  arg->func = PLyList_FromArray;
510  arg->elm->typoid = element_type;
511  arg->elm->typmod = -1;
512  get_type_io_data(element_type, IOFunc_output,
513  &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
514  &arg->elm->typioparam, &funcid);
515  fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
516  }
517 
518  MemoryContextSwitchTo(oldcxt);
519 }
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1840
static PyObject * PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:588
static PyObject * PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:582
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
static PyObject * PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:522
#define OIDOID
Definition: pg_type.h:328
#define NUMERICOID
Definition: pg_type.h:550
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define INT4OID
Definition: pg_type.h:316
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
static PyObject * PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:576
static PyObject * PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:536
PLyDatumToObFunc func
Definition: plpy_typeio.h:21
#define INT2OID
Definition: pg_type.h:308
static PyObject * PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:530
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:604
int32 typmod
Definition: plpy_typeio.h:25
FmgrInfo typfunc
Definition: plpy_typeio.h:22
struct PLyDatumToOb * elm
Definition: plpy_typeio.h:30
int16 typlen
Definition: plpy_typeio.h:28
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:169
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:542
#define FLOAT4OID
Definition: pg_type.h:412
void * palloc0(Size size)
Definition: mcxt.c:878
static PyObject * PLyString_FromDatum(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:614
FmgrInfo typtransform
Definition: plpy_typeio.h:23
#define INT8OID
Definition: pg_type.h:304
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:630
static PyObject * PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:598
#define FLOAT8OID
Definition: pg_type.h:415
#define BOOLOID
Definition: pg_type.h:288
#define BYTEAOID
Definition: pg_type.h:292
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2525
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:624
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2021
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2239
void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, bool *typbyval, char *typalign, char *typdelim, Oid *typioparam, Oid *func)
Definition: lsyscache.c:2043
void PLy_input_tuple_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 105 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyTupleToOb::atts, PLyExecutionContext::curr_proc, elog, ERROR, HeapTupleHeaderGetRawXmin, HeapTupleIsValid, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, PLyProcedure::langid, PLyTypeInfo::mcxt, MemoryContextSwitchTo(), PLyTupleToOb::natts, tupleDesc::natts, ObjectIdGetDatum, OidIsValid, palloc0(), pfree(), PLy_current_execution_context(), PLy_input_datum_func2(), PLyTypeInput::r, RECORDOID, ReleaseSysCache(), RELOID, SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, tupleDesc::tdtypeid, tupleDesc::tdtypmod, PLyProcedure::trftypes, PLyTypeInfo::typ_relid, typeidTypeRelid(), TYPEOID, PLyDatumToOb::typoid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.

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

106 {
107  int i;
109  MemoryContext oldcxt;
110 
111  oldcxt = MemoryContextSwitchTo(arg->mcxt);
112 
113  if (arg->is_rowtype == 0)
114  elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
115  arg->is_rowtype = 1;
116 
117  if (arg->in.r.natts != desc->natts)
118  {
119  if (arg->in.r.atts)
120  pfree(arg->in.r.atts);
121  arg->in.r.natts = desc->natts;
122  arg->in.r.atts = palloc0(desc->natts * sizeof(PLyDatumToOb));
123  }
124 
125  /* Can this be an unnamed tuple? If not, then an Assert would be enough */
126  if (desc->tdtypmod != -1)
127  elog(ERROR, "received unnamed record type as input");
128 
129  Assert(OidIsValid(desc->tdtypeid));
130 
131  /*
132  * RECORDOID means we got called to create input functions for a tuple
133  * fetched by plpy.execute or for an anonymous record type
134  */
135  if (desc->tdtypeid != RECORDOID)
136  {
137  HeapTuple relTup;
138 
139  /* Get the pg_class tuple corresponding to the type of the input */
140  arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
142  if (!HeapTupleIsValid(relTup))
143  elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
144 
145  /* Remember XMIN and TID for later validation if cache is still OK */
147  arg->typrel_tid = relTup->t_self;
148 
149  ReleaseSysCache(relTup);
150  }
151 
152  for (i = 0; i < desc->natts; i++)
153  {
154  HeapTuple typeTup;
155 
156  if (desc->attrs[i]->attisdropped)
157  continue;
158 
159  if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
160  continue; /* already set up this entry */
161 
162  typeTup = SearchSysCache1(TYPEOID,
163  ObjectIdGetDatum(desc->attrs[i]->atttypid));
164  if (!HeapTupleIsValid(typeTup))
165  elog(ERROR, "cache lookup failed for type %u",
166  desc->attrs[i]->atttypid);
167 
168  PLy_input_datum_func2(&(arg->in.r.atts[i]), arg->mcxt,
169  desc->attrs[i]->atttypid,
170  typeTup,
171  exec_ctx->curr_proc->langid,
172  exec_ctx->curr_proc->trftypes);
173 
174  ReleaseSysCache(typeTup);
175  }
176 
177  MemoryContextSwitchTo(oldcxt);
178 }
TransactionId typrel_xmin
Definition: plpy_typeio.h:96
Oid tdtypeid
Definition: tupdesc.h:77
PLyDatumToOb * atts
Definition: plpy_typeio.h:35
Form_pg_attribute * attrs
Definition: tupdesc.h:74
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Oid typeidTypeRelid(Oid type_id)
Definition: parse_type.c:646
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
#define OidIsValid(objectId)
Definition: c.h:538
int natts
Definition: tupdesc.h:73
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
int32 tdtypmod
Definition: tupdesc.h:78
HeapTupleHeader t_data
Definition: htup.h:67
ItemPointerData typrel_tid
Definition: plpy_typeio.h:97
void pfree(void *pointer)
Definition: mcxt.c:950
static void PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:437
PLyTypeInput in
Definition: plpy_typeio.h:86
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RECORDOID
Definition: pg_type.h:676
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void * palloc0(Size size)
Definition: mcxt.c:878
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
PLyTupleToOb r
Definition: plpy_typeio.h:42
MemoryContext mcxt
Definition: plpy_typeio.h:100
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:302
int i
#define elog
Definition: elog.h:219
void PLy_output_datum_func ( PLyTypeInfo arg,
HeapTuple  typeTup,
Oid  langid,
List trftypes 
)

Definition at line 96 of file plpy_typeio.c.

References PLyTypeOutput::d, elog, ERROR, PLyTypeInfo::is_rowtype, PLyTypeInfo::mcxt, PLyTypeInfo::out, and PLy_output_datum_func2().

Referenced by PLy_procedure_create(), and PLy_spi_prepare().

97 {
98  if (arg->is_rowtype > 0)
99  elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
100  arg->is_rowtype = 0;
101  PLy_output_datum_func2(&(arg->out.d), arg->mcxt, typeTup, langid, trftypes);
102 }
#define ERROR
Definition: elog.h:43
PLyObToDatum d
Definition: plpy_typeio.h:77
PLyTypeOutput out
Definition: plpy_typeio.h:87
MemoryContext mcxt
Definition: plpy_typeio.h:100
int is_rowtype
Definition: plpy_typeio.h:93
static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:365
#define elog
Definition: elog.h:219
static void PLy_output_datum_func2 ( PLyObToDatum arg,
MemoryContext  arg_mcxt,
HeapTuple  typeTup,
Oid  langid,
List trftypes 
)
static

Definition at line 365 of file plpy_typeio.c.

References BOOLOID, BYTEAOID, PLyObToDatum::elm, fmgr_info_cxt(), PLyObToDatum::func, get_base_element_type(), get_transform_tosql(), get_type_io_data(), getBaseType(), GETSTRUCT, getTypeIOParam(), HeapTupleGetOid, IOFunc_input, MemoryContextSwitchTo(), palloc0(), PLyObject_ToBool(), PLyObject_ToBytea(), PLyObject_ToComposite(), PLyObject_ToDatum(), PLyObject_ToTransform(), PLySequence_ToArray(), PLyObToDatum::typalign, PLyObToDatum::typbyval, type_is_rowtype(), PLyObToDatum::typfunc, PLyObToDatum::typioparam, PLyObToDatum::typlen, PLyObToDatum::typmod, PLyObToDatum::typoid, PLyObToDatum::typtransform, and TYPTYPE_COMPOSITE.

Referenced by PLy_output_datum_func(), PLy_output_tuple_funcs(), and PLyString_ToComposite().

366 {
367  Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
368  Oid element_type;
369  Oid base_type;
370  Oid funcid;
371  MemoryContext oldcxt;
372 
373  oldcxt = MemoryContextSwitchTo(arg_mcxt);
374 
375  fmgr_info_cxt(typeStruct->typinput, &arg->typfunc, arg_mcxt);
376  arg->typoid = HeapTupleGetOid(typeTup);
377  arg->typmod = -1;
378  arg->typioparam = getTypeIOParam(typeTup);
379  arg->typbyval = typeStruct->typbyval;
380 
381  element_type = get_base_element_type(arg->typoid);
382  base_type = getBaseType(element_type ? element_type : arg->typoid);
383 
384  /*
385  * Select a conversion function to convert Python objects to PostgreSQL
386  * datums.
387  */
388 
389  if ((funcid = get_transform_tosql(base_type, langid, trftypes)))
390  {
392  fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
393  }
394  else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
395  {
397  }
398  else
399  switch (base_type)
400  {
401  case BOOLOID:
402  arg->func = PLyObject_ToBool;
403  break;
404  case BYTEAOID:
405  arg->func = PLyObject_ToBytea;
406  break;
407  default:
408  arg->func = PLyObject_ToDatum;
409  break;
410  }
411 
412  if (element_type)
413  {
414  char dummy_delim;
415  Oid funcid;
416 
417  if (type_is_rowtype(element_type))
419 
420  arg->elm = palloc0(sizeof(*arg->elm));
421  arg->elm->func = arg->func;
422  arg->elm->typtransform = arg->typtransform;
423  arg->func = PLySequence_ToArray;
424 
425  arg->elm->typoid = element_type;
426  arg->elm->typmod = -1;
427  get_type_io_data(element_type, IOFunc_input,
428  &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
429  &arg->elm->typioparam, &funcid);
430  fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
431  }
432 
433  MemoryContextSwitchTo(oldcxt);
434 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:744
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:717
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
int32 typmod
Definition: plpy_typeio.h:61
static Datum PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:962
static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:807
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2372
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:169
void * palloc0(Size size)
Definition: mcxt.c:878
#define BOOLOID
Definition: pg_type.h:288
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:1861
#define BYTEAOID
Definition: pg_type.h:292
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2525
static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:969
struct PLyObToDatum * elm
Definition: plpy_typeio.h:66
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2021
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2239
static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:906
static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:763
FmgrInfo typtransform
Definition: plpy_typeio.h:59
int16 typlen
Definition: plpy_typeio.h:64
void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, bool *typbyval, char *typalign, char *typdelim, Oid *typioparam, Oid *func)
Definition: lsyscache.c:2043
void PLy_output_record_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 251 of file plpy_typeio.c.

References Assert, BlessTupleDesc(), PLyTypeOutput::d, PLyTypeInfo::is_rowtype, PLyTypeInfo::out, PLy_output_tuple_funcs(), tupleDesc::tdtypmod, and PLyObToDatum::typmod.

Referenced by PLy_function_build_args().

252 {
253  /*
254  * If the output record functions are already set, we just have to check
255  * if the record descriptor has not changed
256  */
257  if ((arg->is_rowtype == 1) &&
258  (arg->out.d.typmod != -1) &&
259  (arg->out.d.typmod == desc->tdtypmod))
260  return;
261 
262  /* bless the record to make it known to the typcache lookup code */
263  BlessTupleDesc(desc);
264  /* save the freshly generated typmod */
265  arg->out.d.typmod = desc->tdtypmod;
266  /* proceed with normal I/O function caching */
267  PLy_output_tuple_funcs(arg, desc);
268 
269  /*
270  * it should change is_rowtype to 1, so we won't go through this again
271  * unless the output record description changes
272  */
273  Assert(arg->is_rowtype == 1);
274 }
void PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
Definition: plpy_typeio.c:181
int32 typmod
Definition: plpy_typeio.h:61
int32 tdtypmod
Definition: tupdesc.h:78
PLyObToDatum d
Definition: plpy_typeio.h:77
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1031
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
void PLy_output_tuple_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 181 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, PLyExecutionContext::curr_proc, elog, ERROR, HeapTupleHeaderGetRawXmin, HeapTupleIsValid, i, PLyTypeInfo::is_rowtype, PLyProcedure::langid, PLyTypeInfo::mcxt, MemoryContextSwitchTo(), PLyObToTuple::natts, tupleDesc::natts, ObjectIdGetDatum, OidIsValid, PLyTypeInfo::out, palloc0(), pfree(), PLy_current_execution_context(), PLy_output_datum_func2(), PLyTypeOutput::r, RECORDOID, ReleaseSysCache(), RELOID, SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, tupleDesc::tdtypeid, PLyProcedure::trftypes, PLyTypeInfo::typ_relid, typeidTypeRelid(), TYPEOID, PLyObToDatum::typoid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.

Referenced by PLy_exec_trigger(), PLy_output_record_funcs(), PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), and PLySequence_ToComposite().

182 {
183  int i;
185  MemoryContext oldcxt;
186 
187  oldcxt = MemoryContextSwitchTo(arg->mcxt);
188 
189  if (arg->is_rowtype == 0)
190  elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
191  arg->is_rowtype = 1;
192 
193  if (arg->out.r.natts != desc->natts)
194  {
195  if (arg->out.r.atts)
196  pfree(arg->out.r.atts);
197  arg->out.r.natts = desc->natts;
198  arg->out.r.atts = palloc0(desc->natts * sizeof(PLyObToDatum));
199  }
200 
201  Assert(OidIsValid(desc->tdtypeid));
202 
203  /*
204  * RECORDOID means we got called to create output functions for an
205  * anonymous record type
206  */
207  if (desc->tdtypeid != RECORDOID)
208  {
209  HeapTuple relTup;
210 
211  /* Get the pg_class tuple corresponding to the type of the output */
212  arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
214  if (!HeapTupleIsValid(relTup))
215  elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
216 
217  /* Remember XMIN and TID for later validation if cache is still OK */
219  arg->typrel_tid = relTup->t_self;
220 
221  ReleaseSysCache(relTup);
222  }
223 
224  for (i = 0; i < desc->natts; i++)
225  {
226  HeapTuple typeTup;
227 
228  if (desc->attrs[i]->attisdropped)
229  continue;
230 
231  if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
232  continue; /* already set up this entry */
233 
234  typeTup = SearchSysCache1(TYPEOID,
235  ObjectIdGetDatum(desc->attrs[i]->atttypid));
236  if (!HeapTupleIsValid(typeTup))
237  elog(ERROR, "cache lookup failed for type %u",
238  desc->attrs[i]->atttypid);
239 
240  PLy_output_datum_func2(&(arg->out.r.atts[i]), arg->mcxt, typeTup,
241  exec_ctx->curr_proc->langid,
242  exec_ctx->curr_proc->trftypes);
243 
244  ReleaseSysCache(typeTup);
245  }
246 
247  MemoryContextSwitchTo(oldcxt);
248 }
TransactionId typrel_xmin
Definition: plpy_typeio.h:96
Oid tdtypeid
Definition: tupdesc.h:77
Form_pg_attribute * attrs
Definition: tupdesc.h:74
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Oid typeidTypeRelid(Oid type_id)
Definition: parse_type.c:646
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
#define OidIsValid(objectId)
Definition: c.h:538
int natts
Definition: tupdesc.h:73
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
HeapTupleHeader t_data
Definition: htup.h:67
ItemPointerData typrel_tid
Definition: plpy_typeio.h:97
void pfree(void *pointer)
Definition: mcxt.c:950
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define RECORDOID
Definition: pg_type.h:676
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void * palloc0(Size size)
Definition: mcxt.c:878
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
MemoryContext mcxt
Definition: plpy_typeio.h:100
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
PLyObToTuple r
Definition: plpy_typeio.h:78
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:302
static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:365
int i
PLyObToDatum * atts
Definition: plpy_typeio.h:71
#define elog
Definition: elog.h:219
void PLy_typeinfo_init ( PLyTypeInfo arg,
MemoryContext  mcxt 
)

Definition at line 70 of file plpy_typeio.c.

References PLyTupleToOb::atts, PLyObToTuple::atts, PLyTypeInfo::in, InvalidOid, InvalidTransactionId, PLyTypeInfo::is_rowtype, ItemPointerSetInvalid, PLyTypeInfo::mcxt, PLyTupleToOb::natts, PLyObToTuple::natts, NULL, PLyTypeInfo::out, PLyTypeInput::r, PLyTypeOutput::r, PLyTypeInfo::typ_relid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.

Referenced by PLy_cursor_plan(), PLy_cursor_query(), PLy_procedure_create(), PLy_spi_execute_fetch_result(), PLy_spi_prepare(), PLyObject_ToComposite(), and PLyString_ToComposite().

71 {
72  arg->is_rowtype = -1;
73  arg->in.r.natts = arg->out.r.natts = 0;
74  arg->in.r.atts = NULL;
75  arg->out.r.atts = NULL;
76  arg->typ_relid = InvalidOid;
79  arg->mcxt = mcxt;
80 }
TransactionId typrel_xmin
Definition: plpy_typeio.h:96
PLyDatumToOb * atts
Definition: plpy_typeio.h:35
ItemPointerData typrel_tid
Definition: plpy_typeio.h:97
PLyTypeInput in
Definition: plpy_typeio.h:86
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define InvalidTransactionId
Definition: transam.h:31
PLyTupleToOb r
Definition: plpy_typeio.h:42
#define InvalidOid
Definition: postgres_ext.h:36
MemoryContext mcxt
Definition: plpy_typeio.h:100
#define NULL
Definition: c.h:229
int is_rowtype
Definition: plpy_typeio.h:93
PLyObToTuple r
Definition: plpy_typeio.h:78
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:131
PLyObToDatum * atts
Definition: plpy_typeio.h:71
static PyObject * PLyBool_FromBool ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 522 of file plpy_typeio.c.

References DatumGetBool.

Referenced by PLy_input_datum_func2().

523 {
524  if (DatumGetBool(d))
525  Py_RETURN_TRUE;
526  Py_RETURN_FALSE;
527 }
#define DatumGetBool(X)
Definition: postgres.h:399
static PyObject * PLyBytes_FromBytea ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 604 of file plpy_typeio.c.

References DatumGetByteaPP, PyBytes_FromStringAndSize, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by PLy_input_datum_func2().

605 {
606  text *txt = DatumGetByteaPP(d);
607  char *str = VARDATA_ANY(txt);
608  size_t size = VARSIZE_ANY_EXHDR(txt);
609 
610  return PyBytes_FromStringAndSize(str, size);
611 }
#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:439
static PyObject * PLyDecimal_FromNumeric ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 542 of file plpy_typeio.c.

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

Referenced by PLy_input_datum_func2().

543 {
544  static PyObject *decimal_constructor;
545  char *str;
546  PyObject *pyvalue;
547 
548  /* Try to import cdecimal. If it doesn't exist, fall back to decimal. */
549  if (!decimal_constructor)
550  {
551  PyObject *decimal_module;
552 
553  decimal_module = PyImport_ImportModule("cdecimal");
554  if (!decimal_module)
555  {
556  PyErr_Clear();
557  decimal_module = PyImport_ImportModule("decimal");
558  }
559  if (!decimal_module)
560  PLy_elog(ERROR, "could not import a module for Decimal constructor");
561 
562  decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
563  if (!decimal_constructor)
564  PLy_elog(ERROR, "no Decimal attribute in module");
565  }
566 
568  pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
569  if (!pyvalue)
570  PLy_elog(ERROR, "conversion from numeric to Decimal failed");
571 
572  return pyvalue;
573 }
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:641
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
#define ERROR
Definition: elog.h:43
#define DatumGetCString(X)
Definition: postgres.h:572
PyObject* PLyDict_FromTuple ( PLyTypeInfo info,
HeapTuple  tuple,
TupleDesc  desc 
)

Definition at line 280 of file plpy_typeio.c.

References tupleDesc::attrs, PLyTupleToOb::atts, CurrentMemoryContext, elog, ERROR, PLyDatumToOb::func, heap_getattr, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, MemoryContextReset(), MemoryContextSwitchTo(), NameStr, PLyTupleToOb::natts, NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_current_execution_context(), PLy_elog(), PLy_get_scratch_context(), PLyTypeInput::r, and value.

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

281 {
282  PyObject *volatile dict;
284  MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
285  MemoryContext oldcontext = CurrentMemoryContext;
286 
287  if (info->is_rowtype != 1)
288  elog(ERROR, "PLyTypeInfo structure describes a datum");
289 
290  dict = PyDict_New();
291  if (dict == NULL)
292  PLy_elog(ERROR, "could not create new dictionary");
293 
294  PG_TRY();
295  {
296  int i;
297 
298  /*
299  * Do the work in the scratch context to avoid leaking memory from the
300  * datatype output function calls.
301  */
302  MemoryContextSwitchTo(scratch_context);
303  for (i = 0; i < info->in.r.natts; i++)
304  {
305  char *key;
306  Datum vattr;
307  bool is_null;
308  PyObject *value;
309 
310  if (desc->attrs[i]->attisdropped)
311  continue;
312 
313  key = NameStr(desc->attrs[i]->attname);
314  vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
315 
316  if (is_null || info->in.r.atts[i].func == NULL)
317  PyDict_SetItemString(dict, key, Py_None);
318  else
319  {
320  value = (info->in.r.atts[i].func) (&info->in.r.atts[i], vattr);
321  PyDict_SetItemString(dict, key, value);
322  Py_DECREF(value);
323  }
324  }
325  MemoryContextSwitchTo(oldcontext);
326  MemoryContextReset(scratch_context);
327  }
328  PG_CATCH();
329  {
330  MemoryContextSwitchTo(oldcontext);
331  Py_DECREF(dict);
332  PG_RE_THROW();
333  }
334  PG_END_TRY();
335 
336  return dict;
337 }
PLyDatumToOb * atts
Definition: plpy_typeio.h:35
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
Form_pg_attribute * attrs
Definition: tupdesc.h:74
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
static struct @114 value
PLyTypeInput in
Definition: plpy_typeio.h:86
#define ERROR
Definition: elog.h:43
PLyDatumToObFunc func
Definition: plpy_typeio.h:21
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
uintptr_t Datum
Definition: postgres.h:372
PLyTupleToOb r
Definition: plpy_typeio.h:42
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
int is_rowtype
Definition: plpy_typeio.h:93
#define PG_RE_THROW()
Definition: elog.h:314
int i
#define NameStr(name)
Definition: c.h:499
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:407
static PyObject * PLyFloat_FromFloat4 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 530 of file plpy_typeio.c.

References DatumGetFloat4.

Referenced by PLy_input_datum_func2().

531 {
532  return PyFloat_FromDouble(DatumGetFloat4(d));
533 }
#define DatumGetFloat4(X)
Definition: postgres.h:686
static PyObject * PLyFloat_FromFloat8 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 536 of file plpy_typeio.c.

References DatumGetFloat8.

Referenced by PLy_input_datum_func2().

537 {
538  return PyFloat_FromDouble(DatumGetFloat8(d));
539 }
#define DatumGetFloat8(X)
Definition: postgres.h:734
static Datum PLyGenericObject_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  object,
bool  inarray 
)
static

Definition at line 1328 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, PLyTypeInfo::is_rowtype, NameStr, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, result, value, and values.

Referenced by PLyObject_ToCompositeDatum().

1329 {
1330  Datum result;
1331  HeapTuple tuple;
1332  Datum *values;
1333  bool *nulls;
1334  volatile int i;
1335 
1336  if (info->is_rowtype == 2)
1337  PLy_output_tuple_funcs(info, desc);
1338  Assert(info->is_rowtype == 1);
1339 
1340  /* Build tuple */
1341  values = palloc(sizeof(Datum) * desc->natts);
1342  nulls = palloc(sizeof(bool) * desc->natts);
1343  for (i = 0; i < desc->natts; ++i)
1344  {
1345  char *key;
1346  PyObject *volatile value;
1347  PLyObToDatum *att;
1348 
1349  if (desc->attrs[i]->attisdropped)
1350  {
1351  values[i] = (Datum) 0;
1352  nulls[i] = true;
1353  continue;
1354  }
1355 
1356  key = NameStr(desc->attrs[i]->attname);
1357  value = NULL;
1358  att = &info->out.r.atts[i];
1359  PG_TRY();
1360  {
1361  value = PyObject_GetAttrString(object, key);
1362  if (value == Py_None)
1363  {
1364  values[i] = (Datum) NULL;
1365  nulls[i] = true;
1366  }
1367  else if (value)
1368  {
1369  values[i] = (att->func) (att, -1, value, false);
1370  nulls[i] = false;
1371  }
1372  else
1373  {
1374  /*
1375  * No attribute for this column in the object.
1376  *
1377  * If we are parsing a composite type in an array, a likely
1378  * cause is that the function contained something like "[[123,
1379  * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1380  * array, with a composite type (123, 'foo') in it. But now
1381  * it's interpreted as a two-dimensional array, and we try to
1382  * interpret "123" as the composite type. See also similar
1383  * heuristic in PLyObject_ToDatum().
1384  */
1385  ereport(ERROR,
1386  (errcode(ERRCODE_UNDEFINED_COLUMN),
1387  errmsg("attribute \"%s\" does not exist in Python object", key),
1388  inarray ?
1389  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"") :
1390  errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1391  }
1392 
1393  Py_XDECREF(value);
1394  value = NULL;
1395  }
1396  PG_CATCH();
1397  {
1398  Py_XDECREF(value);
1399  PG_RE_THROW();
1400  }
1401  PG_END_TRY();
1402  }
1403 
1404  tuple = heap_form_tuple(desc, values, nulls);
1405  result = heap_copy_tuple_as_datum(tuple, desc);
1406  heap_freetuple(tuple);
1407 
1408  pfree(values);
1409  pfree(nulls);
1410 
1411  return result;
1412 }
void PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
Definition: plpy_typeio.c:181
int errhint(const char *fmt,...)
Definition: elog.c:987
Form_pg_attribute * attrs
Definition: tupdesc.h:74
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1618
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
static struct @114 value
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define ereport(elevel, rest)
Definition: elog.h:122
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:656
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
PLyObToTuple r
Definition: plpy_typeio.h:78
#define PG_RE_THROW()
Definition: elog.h:314
static Datum values[MAXATTR]
Definition: bootstrap.c:162
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:499
PLyObToDatum * atts
Definition: plpy_typeio.h:71
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
static PyObject * PLyInt_FromInt16 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 576 of file plpy_typeio.c.

References DatumGetInt16.

Referenced by PLy_input_datum_func2().

577 {
578  return PyInt_FromLong(DatumGetInt16(d));
579 }
#define DatumGetInt16(X)
Definition: postgres.h:450
static PyObject * PLyInt_FromInt32 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 582 of file plpy_typeio.c.

References DatumGetInt32.

Referenced by PLy_input_datum_func2().

583 {
584  return PyInt_FromLong(DatumGetInt32(d));
585 }
#define DatumGetInt32(X)
Definition: postgres.h:478
static PyObject * PLyList_FromArray ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 630 of file plpy_typeio.c.

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

Referenced by PLy_input_datum_func2().

631 {
632  ArrayType *array = DatumGetArrayTypeP(d);
633  PLyDatumToOb *elm = arg->elm;
634  int ndim;
635  int *dims;
636  char *dataptr;
637  bits8 *bitmap;
638  int bitmask;
639 
640  if (ARR_NDIM(array) == 0)
641  return PyList_New(0);
642 
643  /* Array dimensions and left bounds */
644  ndim = ARR_NDIM(array);
645  dims = ARR_DIMS(array);
646  Assert(ndim < MAXDIM);
647 
648  /*
649  * We iterate the SQL array in the physical order it's stored in the
650  * datum. For example, for a 3-dimensional array the order of iteration would
651  * be the following: [0,0,0] elements through [0,0,k], then [0,1,0] through
652  * [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till [1,m,k], and so on.
653  *
654  * In Python, there are no multi-dimensional lists as such, but they are
655  * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
656  * list of n m-element arrays, each element of which is k-element array.
657  * PLyList_FromArray_recurse() builds the Python list for a single
658  * dimension, and recurses for the next inner dimension.
659  */
660  dataptr = ARR_DATA_PTR(array);
661  bitmap = ARR_NULLBITMAP(array);
662  bitmask = 1;
663 
664  return PLyList_FromArray_recurse(elm, dims, ndim, 0,
665  &dataptr, &bitmap, &bitmask);
666 }
#define MAXDIM
Definition: c.h:419
#define ARR_DIMS(a)
Definition: array.h:275
#define ARR_DATA_PTR(a)
Definition: array.h:303
struct PLyDatumToOb * elm
Definition: plpy_typeio.h:30
uint8 bits8
Definition: c.h:275
#define Assert(condition)
Definition: c.h:675
#define ARR_NDIM(a)
Definition: array.h:271
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:669
#define ARR_NULLBITMAP(a)
Definition: array.h:281
#define DatumGetArrayTypeP(X)
Definition: array.h:242
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 669 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().

671 {
672  int i;
673  PyObject *list;
674 
675  list = PyList_New(dims[dim]);
676 
677  if (dim < ndim - 1)
678  {
679  /* Outer dimension. Recurse for each inner slice. */
680  for (i = 0; i < dims[dim]; i++)
681  {
682  PyObject *sublist;
683 
684  sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
685  dataptr_p, bitmap_p, bitmask_p);
686  PyList_SET_ITEM(list, i, sublist);
687  }
688  }
689  else
690  {
691  /*
692  * Innermost dimension. Fill the list with the values from the array
693  * for this slice.
694  */
695  char *dataptr = *dataptr_p;
696  bits8 *bitmap = *bitmap_p;
697  int bitmask = *bitmask_p;
698 
699  for (i = 0; i < dims[dim]; i++)
700  {
701  /* checking for NULL */
702  if (bitmap && (*bitmap & bitmask) == 0)
703  {
704  Py_INCREF(Py_None);
705  PyList_SET_ITEM(list, i, Py_None);
706  }
707  else
708  {
709  Datum itemvalue;
710 
711  itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
712  PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
713  dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
714  dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
715  }
716 
717  /* advance bitmap pointer if any */
718  if (bitmap)
719  {
720  bitmask <<= 1;
721  if (bitmask == 0x100 /* (1<<8) */ )
722  {
723  bitmap++;
724  bitmask = 1;
725  }
726  }
727  }
728 
729  *dataptr_p = dataptr;
730  *bitmap_p = bitmap;
731  *bitmask_p = bitmask;
732  }
733 
734  return list;
735 }
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:144
PLyDatumToObFunc func
Definition: plpy_typeio.h:21
int16 typlen
Definition: plpy_typeio.h:28
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:172
uint8 bits8
Definition: c.h:275
uintptr_t Datum
Definition: postgres.h:372
tuple list
Definition: sort-test.py:11
#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:669
static PyObject * PLyLong_FromInt64 ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 588 of file plpy_typeio.c.

References DatumGetInt64.

Referenced by PLy_input_datum_func2().

589 {
590  /* on 32 bit platforms "long" may be too small */
591  if (sizeof(int64) > sizeof(long))
592  return PyLong_FromLongLong(DatumGetInt64(d));
593  else
594  return PyLong_FromLong(DatumGetInt64(d));
595 }
#define DatumGetInt64(X)
Definition: postgres.h:613
static PyObject * PLyLong_FromOid ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 598 of file plpy_typeio.c.

References DatumGetObjectId.

Referenced by PLy_input_datum_func2().

599 {
600  return PyLong_FromUnsignedLong(DatumGetObjectId(d));
601 }
#define DatumGetObjectId(X)
Definition: postgres.h:506
static Datum PLyMapping_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  mapping 
)
static

Definition at line 1163 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, PLyTypeInfo::is_rowtype, NameStr, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, result, value, and values.

Referenced by PLyObject_ToCompositeDatum().

1164 {
1165  Datum result;
1166  HeapTuple tuple;
1167  Datum *values;
1168  bool *nulls;
1169  volatile int i;
1170 
1171  Assert(PyMapping_Check(mapping));
1172 
1173  if (info->is_rowtype == 2)
1174  PLy_output_tuple_funcs(info, desc);
1175  Assert(info->is_rowtype == 1);
1176 
1177  /* Build tuple */
1178  values = palloc(sizeof(Datum) * desc->natts);
1179  nulls = palloc(sizeof(bool) * desc->natts);
1180  for (i = 0; i < desc->natts; ++i)
1181  {
1182  char *key;
1183  PyObject *volatile value;
1184  PLyObToDatum *att;
1185 
1186  if (desc->attrs[i]->attisdropped)
1187  {
1188  values[i] = (Datum) 0;
1189  nulls[i] = true;
1190  continue;
1191  }
1192 
1193  key = NameStr(desc->attrs[i]->attname);
1194  value = NULL;
1195  att = &info->out.r.atts[i];
1196  PG_TRY();
1197  {
1198  value = PyMapping_GetItemString(mapping, key);
1199  if (value == Py_None)
1200  {
1201  values[i] = (Datum) NULL;
1202  nulls[i] = true;
1203  }
1204  else if (value)
1205  {
1206  values[i] = (att->func) (att, -1, value, false);
1207  nulls[i] = false;
1208  }
1209  else
1210  ereport(ERROR,
1211  (errcode(ERRCODE_UNDEFINED_COLUMN),
1212  errmsg("key \"%s\" not found in mapping", key),
1213  errhint("To return null in a column, "
1214  "add the value None to the mapping with the key named after the column.")));
1215 
1216  Py_XDECREF(value);
1217  value = NULL;
1218  }
1219  PG_CATCH();
1220  {
1221  Py_XDECREF(value);
1222  PG_RE_THROW();
1223  }
1224  PG_END_TRY();
1225  }
1226 
1227  tuple = heap_form_tuple(desc, values, nulls);
1228  result = heap_copy_tuple_as_datum(tuple, desc);
1229  heap_freetuple(tuple);
1230 
1231  pfree(values);
1232  pfree(nulls);
1233 
1234  return result;
1235 }
void PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
Definition: plpy_typeio.c:181
int errhint(const char *fmt,...)
Definition: elog.c:987
Form_pg_attribute * attrs
Definition: tupdesc.h:74
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1618
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
static struct @114 value
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define ereport(elevel, rest)
Definition: elog.h:122
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:656
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
PLyObToTuple r
Definition: plpy_typeio.h:78
#define PG_RE_THROW()
Definition: elog.h:314
static Datum values[MAXATTR]
Definition: bootstrap.c:162
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:499
PLyObToDatum * atts
Definition: plpy_typeio.h:71
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
char* PLyObject_AsString ( PyObject *  plrv)

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

849 {
850  PyObject *plrv_bo;
851  char *plrv_sc;
852  size_t plen;
853  size_t slen;
854 
855  if (PyUnicode_Check(plrv))
856  plrv_bo = PLyUnicode_Bytes(plrv);
857  else if (PyFloat_Check(plrv))
858  {
859  /* use repr() for floats, str() is lossy */
860 #if PY_MAJOR_VERSION >= 3
861  PyObject *s = PyObject_Repr(plrv);
862 
863  plrv_bo = PLyUnicode_Bytes(s);
864  Py_XDECREF(s);
865 #else
866  plrv_bo = PyObject_Repr(plrv);
867 #endif
868  }
869  else
870  {
871 #if PY_MAJOR_VERSION >= 3
872  PyObject *s = PyObject_Str(plrv);
873 
874  plrv_bo = PLyUnicode_Bytes(s);
875  Py_XDECREF(s);
876 #else
877  plrv_bo = PyObject_Str(plrv);
878 #endif
879  }
880  if (!plrv_bo)
881  PLy_elog(ERROR, "could not create string representation of Python object");
882 
883  plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
884  plen = PyBytes_Size(plrv_bo);
885  slen = strlen(plrv_sc);
886 
887  Py_XDECREF(plrv_bo);
888 
889  if (slen < plen)
890  ereport(ERROR,
891  (errcode(ERRCODE_DATATYPE_MISMATCH),
892  errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
893  else if (slen > plen)
894  elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
895  pg_verifymbstr(plrv_sc, slen, false);
896 
897  return plrv_sc;
898 }
char * pstrdup(const char *in)
Definition: mcxt.c:1077
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
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
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
static PyObject * PLyObject_FromTransform ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 624 of file plpy_typeio.c.

References DatumGetPointer, FunctionCall1, and PLyDatumToOb::typtransform.

Referenced by PLy_input_datum_func2().

625 {
626  return (PyObject *) DatumGetPointer(FunctionCall1(&arg->typtransform, d));
627 }
FmgrInfo typtransform
Definition: plpy_typeio.h:23
#define DatumGetPointer(X)
Definition: postgres.h:555
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:602
static Datum PLyObject_ToBool ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 744 of file plpy_typeio.c.

References Assert, BoolGetDatum, domain_check(), FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typtype(), PLyObToDatum::typfunc, PLyObToDatum::typoid, and TYPTYPE_DOMAIN.

Referenced by PLy_output_datum_func2().

745 {
746  Datum rv;
747 
748  Assert(plrv != Py_None);
749  rv = BoolGetDatum(PyObject_IsTrue(plrv));
750 
751  if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
752  domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
753 
754  return rv;
755 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
#define TYPTYPE_DOMAIN
Definition: pg_type.h:718
MemoryContext fn_mcxt
Definition: fmgr.h:65
char get_typtype(Oid typid)
Definition: lsyscache.c:2347
uintptr_t Datum
Definition: postgres.h:372
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:326
#define BoolGetDatum(X)
Definition: postgres.h:408
#define Assert(condition)
Definition: c.h:675
void * fn_extra
Definition: fmgr.h:64
static Datum PLyObject_ToBytea ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 763 of file plpy_typeio.c.

References Assert, domain_check(), ERROR, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typtype(), NULL, palloc(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_elog(), PointerGetDatum, PyBytes_AsString, PyBytes_Size, PyObject_Bytes, result, SET_VARSIZE, PLyObToDatum::typfunc, PLyObToDatum::typoid, TYPTYPE_DOMAIN, VARDATA, and VARHDRSZ.

Referenced by PLy_output_datum_func2().

764 {
765  PyObject *volatile plrv_so = NULL;
766  Datum rv;
767 
768  Assert(plrv != Py_None);
769 
770  plrv_so = PyObject_Bytes(plrv);
771  if (!plrv_so)
772  PLy_elog(ERROR, "could not create bytes representation of Python object");
773 
774  PG_TRY();
775  {
776  char *plrv_sc = PyBytes_AsString(plrv_so);
777  size_t len = PyBytes_Size(plrv_so);
778  size_t size = len + VARHDRSZ;
779  bytea *result = palloc(size);
780 
781  SET_VARSIZE(result, size);
782  memcpy(VARDATA(result), plrv_sc, len);
783  rv = PointerGetDatum(result);
784  }
785  PG_CATCH();
786  {
787  Py_XDECREF(plrv_so);
788  PG_RE_THROW();
789  }
790  PG_END_TRY();
791 
792  Py_XDECREF(plrv_so);
793 
794  if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
795  domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
796 
797  return rv;
798 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
#define TYPTYPE_DOMAIN
Definition: pg_type.h:718
#define VARDATA(PTR)
Definition: postgres.h:303
MemoryContext fn_mcxt
Definition: fmgr.h:65
#define PyObject_Bytes
Definition: plpython.h:87
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:445
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
char get_typtype(Oid typid)
Definition: lsyscache.c:2347
return result
Definition: formatting.c:1618
#define PyBytes_AsString
Definition: plpython.h:84
#define ERROR
Definition: elog.h:43
#define PyBytes_Size
Definition: plpython.h:86
uintptr_t Datum
Definition: postgres.h:372
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:326
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define PG_RE_THROW()
Definition: elog.h:314
void * fn_extra
Definition: fmgr.h:64
void * palloc(Size size)
Definition: mcxt.c:849
Definition: c.h:439
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
static Datum PLyObject_ToComposite ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 807 of file plpy_typeio.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), CurrentMemoryContext, elog, ERROR, PLyTypeInfo::is_rowtype, lookup_rowtype_tupdesc(), MemoryContextDelete(), MemSet, PLy_typeinfo_init(), PLyObject_ToCompositeDatum(), ReleaseTupleDesc, PLyObToDatum::typmod, and PLyObToDatum::typoid.

Referenced by PLy_output_datum_func2().

808 {
809  Datum rv;
810  PLyTypeInfo info;
811  TupleDesc desc;
812  MemoryContext cxt;
813 
814  if (typmod != -1)
815  elog(ERROR, "received unnamed record type as input");
816 
817  /* Create a dummy PLyTypeInfo */
819  "PL/Python temp context",
821  MemSet(&info, 0, sizeof(PLyTypeInfo));
822  PLy_typeinfo_init(&info, cxt);
823  /* Mark it as needing output routines lookup */
824  info.is_rowtype = 2;
825 
826  desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
827 
828  /*
829  * This will set up the dummy PLyTypeInfo's output conversion routines,
830  * since we left is_rowtype as 2. A future optimization could be caching
831  * that info instead of looking it up every time a tuple is returned from
832  * the function.
833  */
834  rv = PLyObject_ToCompositeDatum(&info, desc, plrv, inarray);
835 
836  ReleaseTupleDesc(desc);
837 
838  MemoryContextDelete(cxt);
839 
840  return rv;
841 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
Definition: plpy_typeio.c:70
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1257
#define MemSet(start, val, len)
Definition: c.h:857
int32 typmod
Definition: plpy_typeio.h:61
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
uintptr_t Datum
Definition: postgres.h:372
int is_rowtype
Definition: plpy_typeio.h:93
Datum PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:345
#define elog
Definition: elog.h:219
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:107
Datum PLyObject_ToCompositeDatum ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  plrv,
bool  inarray 
)

Definition at line 345 of file plpy_typeio.c.

References PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), PLySequence_ToComposite(), and PLyString_ToComposite().

Referenced by PLy_exec_function(), and PLyObject_ToComposite().

346 {
347  Datum datum;
348 
349  if (PyString_Check(plrv) || PyUnicode_Check(plrv))
350  datum = PLyString_ToComposite(info, desc, plrv, inarray);
351  else if (PySequence_Check(plrv))
352  /* composite type as sequence (tuple, list etc) */
353  datum = PLySequence_ToComposite(info, desc, plrv);
354  else if (PyMapping_Check(plrv))
355  /* composite type as mapping (currently only dict) */
356  datum = PLyMapping_ToComposite(info, desc, plrv);
357  else
358  /* returned as smth, must provide method __getattr__(name) */
359  datum = PLyGenericObject_ToComposite(info, desc, plrv, inarray);
360 
361  return datum;
362 }
static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray)
Definition: plpy_typeio.c:1129
uintptr_t Datum
Definition: postgres.h:372
static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray)
Definition: plpy_typeio.c:1328
static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
Definition: plpy_typeio.c:1163
static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
Definition: plpy_typeio.c:1239
static Datum PLyObject_ToDatum ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 906 of file plpy_typeio.c.

References Assert, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, FmgrInfo::fn_oid, InputFunctionCall(), PLyObject_AsString(), PLyObToDatum::typfunc, and PLyObToDatum::typioparam.

Referenced by PLy_output_datum_func2(), and PLyString_ToComposite().

907 {
908  char *str;
909 
910  Assert(plrv != Py_None);
911 
912  str = PLyObject_AsString(plrv);
913 
914  /*
915  * If we are parsing a composite type within an array, and the string
916  * isn't a valid record literal, there's a high chance that the function
917  * did something like:
918  *
919  * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
920  * LANGUAGE plpython;
921  *
922  * Before PostgreSQL 10, that was interpreted as a single-dimensional
923  * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
924  * for multi-dimensional arrays, and it is now interpreted as a
925  * two-dimensional array, containing two records, 'foo', and 'bar'.
926  * record_in() will throw an error, because "foo" is not a valid record
927  * literal.
928  *
929  * To make that less confusing to users who are upgrading from older
930  * versions, try to give a hint in the typical instances of that. If we are
931  * parsing an array of composite types, and we see a string literal that
932  * is not a valid record literal, give a hint. We only want to give the
933  * hint in the narrow case of a malformed string literal, not any error
934  * from record_in(), so check for that case here specifically.
935  *
936  * This check better match the one in record_in(), so that we don't forbid
937  * literals that are actually valid!
938  */
939  if (inarray && arg->typfunc.fn_oid == F_RECORD_IN)
940  {
941  char *ptr = str;
942 
943  /* Allow leading whitespace */
944  while (*ptr && isspace((unsigned char) *ptr))
945  ptr++;
946  if (*ptr++ != '(')
947  ereport(ERROR,
948  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
949  errmsg("malformed record literal: \"%s\"", str),
950  errdetail("Missing left parenthesis."),
951  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"")));
952  }
953 
954  return InputFunctionCall(&arg->typfunc,
955  str,
956  arg->typioparam,
957  typmod);
958 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:848
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1932
Oid fn_oid
Definition: fmgr.h:59
#define Assert(condition)
Definition: c.h:675
int errmsg(const char *fmt,...)
Definition: elog.c:797
static Datum PLyObject_ToTransform ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 962 of file plpy_typeio.c.

References FunctionCall1, PointerGetDatum, and PLyObToDatum::typtransform.

Referenced by PLy_output_datum_func2().

963 {
964  return FunctionCall1(&arg->typtransform, PointerGetDatum(plrv));
965 }
#define PointerGetDatum(X)
Definition: postgres.h:562
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:602
FmgrInfo typtransform
Definition: plpy_typeio.h:59
static Datum PLySequence_ToArray ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

Definition at line 969 of file plpy_typeio.c.

References Assert, construct_md_array(), domain_check(), PLyObToDatum::elm, ERROR, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_base_element_type(), get_typtype(), i, MaxAllocSize, MAXDIM, next, palloc(), PLy_elog(), PLySequence_ToArray_recurse(), PointerGetDatum, PLyObToDatum::typalign, PLyObToDatum::typbyval, PLyObToDatum::typfunc, PLyObToDatum::typlen, PLyObToDatum::typoid, and TYPTYPE_DOMAIN.

Referenced by PLy_output_datum_func2().

970 {
971  ArrayType *array;
972  int i;
973  Datum *elems;
974  bool *nulls;
975  int64 len;
976  int ndim;
977  int dims[MAXDIM];
978  int lbs[MAXDIM];
979  int currelem;
980  Datum rv;
981  PyObject *pyptr = plrv;
982  PyObject *next;
983 
984  Assert(plrv != Py_None);
985 
986  /*
987  * Determine the number of dimensions, and their sizes.
988  */
989  ndim = 0;
990  len = 1;
991 
992  Py_INCREF(plrv);
993 
994  for (;;)
995  {
996  if (!PyList_Check(pyptr))
997  break;
998 
999  if (ndim == MAXDIM)
1000  PLy_elog(ERROR, "number of array dimensions exceeds the maximum allowed (%d)", MAXDIM);
1001 
1002  dims[ndim] = PySequence_Length(pyptr);
1003  if (dims[ndim] < 0)
1004  PLy_elog(ERROR, "cannot determine sequence length for function return value");
1005 
1006  if (dims[ndim] > MaxAllocSize)
1007  PLy_elog(ERROR, "array size exceeds the maximum allowed");
1008 
1009  len *= dims[ndim];
1010  if (len > MaxAllocSize)
1011  PLy_elog(ERROR, "array size exceeds the maximum allowed");
1012 
1013  if (dims[ndim] == 0)
1014  {
1015  /* empty sequence */
1016  break;
1017  }
1018 
1019  ndim++;
1020 
1021  next = PySequence_GetItem(pyptr, 0);
1022  Py_XDECREF(pyptr);
1023  pyptr = next;
1024  }
1025  Py_XDECREF(pyptr);
1026 
1027  /*
1028  * Check for zero dimensions. This happens if the object is a tuple or a
1029  * string, rather than a list, or is not a sequence at all. We don't map
1030  * tuples or strings to arrays in general, but in the first level, be
1031  * lenient, for historical reasons. So if the object is a sequence of any
1032  * kind, treat it as a one-dimensional array.
1033  */
1034  if (ndim == 0)
1035  {
1036  if (!PySequence_Check(plrv))
1037  PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");
1038 
1039  ndim = 1;
1040  len = dims[0] = PySequence_Length(plrv);
1041  }
1042 
1043  /*
1044  * Traverse the Python lists, in depth-first order, and collect all the
1045  * elements at the bottom level into 'elems'/'nulls' arrays.
1046  */
1047  elems = palloc(sizeof(Datum) * len);
1048  nulls = palloc(sizeof(bool) * len);
1049  currelem = 0;
1050  PLySequence_ToArray_recurse(arg->elm, plrv,
1051  dims, ndim, 0,
1052  elems, nulls, &currelem);
1053 
1054  for (i = 0; i < ndim; i++)
1055  lbs[i] = 1;
1056 
1057  array = construct_md_array(elems,
1058  nulls,
1059  ndim,
1060  dims,
1061  lbs,
1063  arg->elm->typlen,
1064  arg->elm->typbyval,
1065  arg->elm->typalign);
1066 
1067  /*
1068  * If the result type is a domain of array, the resulting array must be
1069  * checked.
1070  */
1071  rv = PointerGetDatum(array);
1072  if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
1073  domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
1074  return rv;
1075 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
#define TYPTYPE_DOMAIN
Definition: pg_type.h:718
static int32 next
Definition: blutils.c:210
MemoryContext fn_mcxt
Definition: fmgr.h:65
#define MAXDIM
Definition: c.h:419
#define PointerGetDatum(X)
Definition: postgres.h:562
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
char get_typtype(Oid typid)
Definition: lsyscache.c:2347
#define ERROR
Definition: elog.h:43
#define MaxAllocSize
Definition: memutils.h:40
uintptr_t Datum
Definition: postgres.h:372
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:326
#define Assert(condition)
Definition: c.h:675
void * fn_extra
Definition: fmgr.h:64
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2525
struct PLyObToDatum * elm
Definition: plpy_typeio.h:66
void * palloc(Size size)
Definition: mcxt.c:849
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:3340
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:1082
int16 typlen
Definition: plpy_typeio.h:64
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 1082 of file plpy_typeio.c.

References ERROR, PLyObToDatum::func, i, and PLy_elog().

Referenced by PLySequence_ToArray().

1085 {
1086  int i;
1087 
1088  if (PySequence_Length(list) != dims[dim])
1089  PLy_elog(ERROR,
1090  "multidimensional arrays must have array expressions with matching dimensions. "
1091  "PL/Python function return value has sequence length %d while expected %d",
1092  (int) PySequence_Length(list), dims[dim]);
1093 
1094  if (dim < ndim - 1)
1095  {
1096  for (i = 0; i < dims[dim]; i++)
1097  {
1098  PyObject *sublist = PySequence_GetItem(list, i);
1099 
1100  PLySequence_ToArray_recurse(elm, sublist, dims, ndim, dim + 1,
1101  elems, nulls, currelem);
1102  Py_XDECREF(sublist);
1103  }
1104  }
1105  else
1106  {
1107  for (i = 0; i < dims[dim]; i++)
1108  {
1109  PyObject *obj = PySequence_GetItem(list, i);
1110 
1111  if (obj == Py_None)
1112  {
1113  nulls[*currelem] = true;
1114  elems[*currelem] = (Datum) 0;
1115  }
1116  else
1117  {
1118  nulls[*currelem] = false;
1119  elems[*currelem] = elm->func(elm, -1, obj, true);
1120  }
1121  Py_XDECREF(obj);
1122  (*currelem)++;
1123  }
1124  }
1125 }
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:372
tuple list
Definition: sort-test.py:11
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:1082
static Datum PLySequence_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  sequence 
)
static

Definition at line 1239 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errmsg(), ERROR, PLyObToDatum::func, heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, idx(), PLyTypeInfo::is_rowtype, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, result, value, and values.

Referenced by PLyObject_ToCompositeDatum().

1240 {
1241  Datum result;
1242  HeapTuple tuple;
1243  Datum *values;
1244  bool *nulls;
1245  volatile int idx;
1246  volatile int i;
1247 
1248  Assert(PySequence_Check(sequence));
1249 
1250  /*
1251  * Check that sequence length is exactly same as PG tuple's. We actually
1252  * can ignore exceeding items or assume missing ones as null but to avoid
1253  * plpython developer's errors we are strict here
1254  */
1255  idx = 0;
1256  for (i = 0; i < desc->natts; i++)
1257  {
1258  if (!desc->attrs[i]->attisdropped)
1259  idx++;
1260  }
1261  if (PySequence_Length(sequence) != idx)
1262  ereport(ERROR,
1263  (errcode(ERRCODE_DATATYPE_MISMATCH),
1264  errmsg("length of returned sequence did not match number of columns in row")));
1265 
1266  if (info->is_rowtype == 2)
1267  PLy_output_tuple_funcs(info, desc);
1268  Assert(info->is_rowtype == 1);
1269 
1270  /* Build tuple */
1271  values = palloc(sizeof(Datum) * desc->natts);
1272  nulls = palloc(sizeof(bool) * desc->natts);
1273  idx = 0;
1274  for (i = 0; i < desc->natts; ++i)
1275  {
1276  PyObject *volatile value;
1277  PLyObToDatum *att;
1278 
1279  if (desc->attrs[i]->attisdropped)
1280  {
1281  values[i] = (Datum) 0;
1282  nulls[i] = true;
1283  continue;
1284  }
1285 
1286  value = NULL;
1287  att = &info->out.r.atts[i];
1288  PG_TRY();
1289  {
1290  value = PySequence_GetItem(sequence, idx);
1291  Assert(value);
1292  if (value == Py_None)
1293  {
1294  values[i] = (Datum) NULL;
1295  nulls[i] = true;
1296  }
1297  else if (value)
1298  {
1299  values[i] = (att->func) (att, -1, value, false);
1300  nulls[i] = false;
1301  }
1302 
1303  Py_XDECREF(value);
1304  value = NULL;
1305  }
1306  PG_CATCH();
1307  {
1308  Py_XDECREF(value);
1309  PG_RE_THROW();
1310  }
1311  PG_END_TRY();
1312 
1313  idx++;
1314  }
1315 
1316  tuple = heap_form_tuple(desc, values, nulls);
1317  result = heap_copy_tuple_as_datum(tuple, desc);
1318  heap_freetuple(tuple);
1319 
1320  pfree(values);
1321  pfree(nulls);
1322 
1323  return result;
1324 }
void PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
Definition: plpy_typeio.c:181
Form_pg_attribute * attrs
Definition: tupdesc.h:74
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
return result
Definition: formatting.c:1618
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
static struct @114 value
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
PLyTypeOutput out
Definition: plpy_typeio.h:87
#define ereport(elevel, rest)
Definition: elog.h:122
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:656
uintptr_t Datum
Definition: postgres.h:372
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int is_rowtype
Definition: plpy_typeio.h:93
PLyObToTuple r
Definition: plpy_typeio.h:78
#define PG_RE_THROW()
Definition: elog.h:314
static Datum values[MAXATTR]
Definition: bootstrap.c:162
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
PLyObToDatum * atts
Definition: plpy_typeio.h:71
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
static PyObject * PLyString_FromDatum ( PLyDatumToOb arg,
Datum  d 
)
static

Definition at line 614 of file plpy_typeio.c.

References OutputFunctionCall(), pfree(), and PLyDatumToOb::typfunc.

Referenced by PLy_input_datum_func2().

615 {
616  char *x = OutputFunctionCall(&arg->typfunc, d);
617  PyObject *r = PyString_FromString(x);
618 
619  pfree(x);
620  return r;
621 }
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1976
void pfree(void *pointer)
Definition: mcxt.c:950
FmgrInfo typfunc
Definition: plpy_typeio.h:22
static Datum PLyString_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  string,
bool  inarray 
)
static

Definition at line 1129 of file plpy_typeio.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), PLyExecutionContext::curr_proc, CurrentMemoryContext, PLyTypeOutput::d, elog, ERROR, HeapTupleIsValid, PLyProcedure::langid, PLyTypeInfo::mcxt, MemoryContextDelete(), MemSet, ObjectIdGetDatum, PLyTypeInfo::out, PLy_current_execution_context(), PLy_output_datum_func2(), PLy_typeinfo_init(), PLyObject_ToDatum(), ReleaseSysCache(), result, SearchSysCache1, tupleDesc::tdtypeid, tupleDesc::tdtypmod, PLyProcedure::trftypes, and TYPEOID.

Referenced by PLyObject_ToCompositeDatum().

1130 {
1131  Datum result;
1132  HeapTuple typeTup;
1133  PLyTypeInfo locinfo;
1135  MemoryContext cxt;
1136 
1137  /* Create a dummy PLyTypeInfo */
1139  "PL/Python temp context",
1141  MemSet(&locinfo, 0, sizeof(PLyTypeInfo));
1142  PLy_typeinfo_init(&locinfo, cxt);
1143 
1144  typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid));
1145  if (!HeapTupleIsValid(typeTup))
1146  elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
1147 
1148  PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup,
1149  exec_ctx->curr_proc->langid,
1150  exec_ctx->curr_proc->trftypes);
1151 
1152  ReleaseSysCache(typeTup);
1153 
1154  result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string, inarray);
1155 
1156  MemoryContextDelete(cxt);
1157 
1158  return result;
1159 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
Oid tdtypeid
Definition: tupdesc.h:77
void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
Definition: plpy_typeio.c:70
#define MemSet(start, val, len)
Definition: c.h:857
return result
Definition: formatting.c:1618
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
int32 tdtypmod
Definition: tupdesc.h:78
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
PLyObToDatum d
Definition: plpy_typeio.h:77
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
PLyTypeOutput out
Definition: plpy_typeio.h:87
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
PLyProcedure * curr_proc
Definition: plpy_main.h:20
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
MemoryContext mcxt
Definition: plpy_typeio.h:100
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:365
#define elog
Definition: elog.h:219
static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:906