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:1872
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:554
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:137
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:542
#define FLOAT4OID
Definition: pg_type.h:416
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:419
#define BOOLOID
Definition: pg_type.h:288
#define BYTEAOID
Definition: pg_type.h:292
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2557
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:624
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2053
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2271
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:2075
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:156
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:680
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void * palloc0(Size size)
Definition: mcxt.c:878
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
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:745
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
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:963
static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:808
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2404
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
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:1893
#define BYTEAOID
Definition: pg_type.h:292
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2557
static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:970
struct PLyObToDatum * elm
Definition: plpy_typeio.h:66
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2053
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2271
static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:907
static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
Definition: plpy_typeio.c:764
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:2075
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:156
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:680
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void * palloc0(Size size)
Definition: mcxt.c:878
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
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:150
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
PLyTypeInput in
Definition: plpy_typeio.h:86
#define ERROR
Definition: elog.h:43
PLyDatumToObFunc func
Definition: plpy_typeio.h:21
static struct @121 value
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 1329 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().

1330 {
1331  Datum result;
1332  HeapTuple tuple;
1333  Datum *values;
1334  bool *nulls;
1335  volatile int i;
1336 
1337  if (info->is_rowtype == 2)
1338  PLy_output_tuple_funcs(info, desc);
1339  Assert(info->is_rowtype == 1);
1340 
1341  /* Build tuple */
1342  values = palloc(sizeof(Datum) * desc->natts);
1343  nulls = palloc(sizeof(bool) * desc->natts);
1344  for (i = 0; i < desc->natts; ++i)
1345  {
1346  char *key;
1347  PyObject *volatile value;
1348  PLyObToDatum *att;
1349 
1350  if (desc->attrs[i]->attisdropped)
1351  {
1352  values[i] = (Datum) 0;
1353  nulls[i] = true;
1354  continue;
1355  }
1356 
1357  key = NameStr(desc->attrs[i]->attname);
1358  value = NULL;
1359  att = &info->out.r.atts[i];
1360  PG_TRY();
1361  {
1362  value = PyObject_GetAttrString(object, key);
1363  if (value == Py_None)
1364  {
1365  values[i] = (Datum) NULL;
1366  nulls[i] = true;
1367  }
1368  else if (value)
1369  {
1370  values[i] = (att->func) (att, -1, value, false);
1371  nulls[i] = false;
1372  }
1373  else
1374  {
1375  /*
1376  * No attribute for this column in the object.
1377  *
1378  * If we are parsing a composite type in an array, a likely
1379  * cause is that the function contained something like "[[123,
1380  * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1381  * array, with a composite type (123, 'foo') in it. But now
1382  * it's interpreted as a two-dimensional array, and we try to
1383  * interpret "123" as the composite type. See also similar
1384  * heuristic in PLyObject_ToDatum().
1385  */
1386  ereport(ERROR,
1387  (errcode(ERRCODE_UNDEFINED_COLUMN),
1388  errmsg("attribute \"%s\" does not exist in Python object", key),
1389  inarray ?
1390  errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"") :
1391  errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1392  }
1393 
1394  Py_XDECREF(value);
1395  value = NULL;
1396  }
1397  PG_CATCH();
1398  {
1399  Py_XDECREF(value);
1400  PG_RE_THROW();
1401  }
1402  PG_END_TRY();
1403  }
1404 
1405  tuple = heap_form_tuple(desc, values, nulls);
1406  result = heap_copy_tuple_as_datum(tuple, desc);
1407  heap_freetuple(tuple);
1408 
1409  pfree(values);
1410  pfree(nulls);
1411 
1412  return result;
1413 }
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:1633
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
static struct @121 value
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:163
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
651  * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0]
652  * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till
653  * [1,m,k], and so on.
654  *
655  * In Python, there are no multi-dimensional lists as such, but they are
656  * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
657  * list of n m-element arrays, each element of which is k-element array.
658  * PLyList_FromArray_recurse() builds the Python list for a single
659  * dimension, and recurses for the next inner dimension.
660  */
661  dataptr = ARR_DATA_PTR(array);
662  bitmap = ARR_NULLBITMAP(array);
663  bitmask = 1;
664 
665  return PLyList_FromArray_recurse(elm, dims, ndim, 0,
666  &dataptr, &bitmap, &bitmask);
667 }
#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:670
#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 670 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().

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

1165 {
1166  Datum result;
1167  HeapTuple tuple;
1168  Datum *values;
1169  bool *nulls;
1170  volatile int i;
1171 
1172  Assert(PyMapping_Check(mapping));
1173 
1174  if (info->is_rowtype == 2)
1175  PLy_output_tuple_funcs(info, desc);
1176  Assert(info->is_rowtype == 1);
1177 
1178  /* Build tuple */
1179  values = palloc(sizeof(Datum) * desc->natts);
1180  nulls = palloc(sizeof(bool) * desc->natts);
1181  for (i = 0; i < desc->natts; ++i)
1182  {
1183  char *key;
1184  PyObject *volatile value;
1185  PLyObToDatum *att;
1186 
1187  if (desc->attrs[i]->attisdropped)
1188  {
1189  values[i] = (Datum) 0;
1190  nulls[i] = true;
1191  continue;
1192  }
1193 
1194  key = NameStr(desc->attrs[i]->attname);
1195  value = NULL;
1196  att = &info->out.r.atts[i];
1197  PG_TRY();
1198  {
1199  value = PyMapping_GetItemString(mapping, key);
1200  if (value == Py_None)
1201  {
1202  values[i] = (Datum) NULL;
1203  nulls[i] = true;
1204  }
1205  else if (value)
1206  {
1207  values[i] = (att->func) (att, -1, value, false);
1208  nulls[i] = false;
1209  }
1210  else
1211  ereport(ERROR,
1212  (errcode(ERRCODE_UNDEFINED_COLUMN),
1213  errmsg("key \"%s\" not found in mapping", key),
1214  errhint("To return null in a column, "
1215  "add the value None to the mapping with the key named after the column.")));
1216 
1217  Py_XDECREF(value);
1218  value = NULL;
1219  }
1220  PG_CATCH();
1221  {
1222  Py_XDECREF(value);
1223  PG_RE_THROW();
1224  }
1225  PG_END_TRY();
1226  }
1227 
1228  tuple = heap_form_tuple(desc, values, nulls);
1229  result = heap_copy_tuple_as_datum(tuple, desc);
1230  heap_freetuple(tuple);
1231 
1232  pfree(values);
1233  pfree(nulls);
1234 
1235  return result;
1236 }
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:1633
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
static struct @121 value
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:163
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 849 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().

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

746 {
747  Datum rv;
748 
749  Assert(plrv != Py_None);
750  rv = BoolGetDatum(PyObject_IsTrue(plrv));
751 
752  if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
753  domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
754 
755  return rv;
756 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
MemoryContext fn_mcxt
Definition: fmgr.h:65
char get_typtype(Oid typid)
Definition: lsyscache.c:2379
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 764 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().

765 {
766  PyObject *volatile plrv_so = NULL;
767  Datum rv;
768 
769  Assert(plrv != Py_None);
770 
771  plrv_so = PyObject_Bytes(plrv);
772  if (!plrv_so)
773  PLy_elog(ERROR, "could not create bytes representation of Python object");
774 
775  PG_TRY();
776  {
777  char *plrv_sc = PyBytes_AsString(plrv_so);
778  size_t len = PyBytes_Size(plrv_so);
779  size_t size = len + VARHDRSZ;
780  bytea *result = palloc(size);
781 
782  SET_VARSIZE(result, size);
783  memcpy(VARDATA(result), plrv_sc, len);
784  rv = PointerGetDatum(result);
785  }
786  PG_CATCH();
787  {
788  Py_XDECREF(plrv_so);
789  PG_RE_THROW();
790  }
791  PG_END_TRY();
792 
793  Py_XDECREF(plrv_so);
794 
795  if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
796  domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
797 
798  return rv;
799 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
#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:2379
return result
Definition: formatting.c:1633
#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 808 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().

809 {
810  Datum rv;
811  PLyTypeInfo info;
812  TupleDesc desc;
813  MemoryContext cxt;
814 
815  if (typmod != -1)
816  elog(ERROR, "received unnamed record type as input");
817 
818  /* Create a dummy PLyTypeInfo */
820  "PL/Python temp context",
822  MemSet(&info, 0, sizeof(PLyTypeInfo));
823  PLy_typeinfo_init(&info, cxt);
824  /* Mark it as needing output routines lookup */
825  info.is_rowtype = 2;
826 
827  desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
828 
829  /*
830  * This will set up the dummy PLyTypeInfo's output conversion routines,
831  * since we left is_rowtype as 2. A future optimization could be caching
832  * that info instead of looking it up every time a tuple is returned from
833  * the function.
834  */
835  rv = PLyObject_ToCompositeDatum(&info, desc, plrv, inarray);
836 
837  ReleaseTupleDesc(desc);
838 
839  MemoryContextDelete(cxt);
840 
841  return rv;
842 }
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:1130
uintptr_t Datum
Definition: postgres.h:372
static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray)
Definition: plpy_typeio.c:1329
static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
Definition: plpy_typeio.c:1164
static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
Definition: plpy_typeio.c:1240
static Datum PLyObject_ToDatum ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv,
bool  inarray 
)
static

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

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

References FunctionCall1, PointerGetDatum, and PLyObToDatum::typtransform.

Referenced by PLy_output_datum_func2().

964 {
965  return FunctionCall1(&arg->typtransform, PointerGetDatum(plrv));
966 }
#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 970 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().

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

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

Referenced by PLySequence_ToArray().

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

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

1241 {
1242  Datum result;
1243  HeapTuple tuple;
1244  Datum *values;
1245  bool *nulls;
1246  volatile int idx;
1247  volatile int i;
1248 
1249  Assert(PySequence_Check(sequence));
1250 
1251  /*
1252  * Check that sequence length is exactly same as PG tuple's. We actually
1253  * can ignore exceeding items or assume missing ones as null but to avoid
1254  * plpython developer's errors we are strict here
1255  */
1256  idx = 0;
1257  for (i = 0; i < desc->natts; i++)
1258  {
1259  if (!desc->attrs[i]->attisdropped)
1260  idx++;
1261  }
1262  if (PySequence_Length(sequence) != idx)
1263  ereport(ERROR,
1264  (errcode(ERRCODE_DATATYPE_MISMATCH),
1265  errmsg("length of returned sequence did not match number of columns in row")));
1266 
1267  if (info->is_rowtype == 2)
1268  PLy_output_tuple_funcs(info, desc);
1269  Assert(info->is_rowtype == 1);
1270 
1271  /* Build tuple */
1272  values = palloc(sizeof(Datum) * desc->natts);
1273  nulls = palloc(sizeof(bool) * desc->natts);
1274  idx = 0;
1275  for (i = 0; i < desc->natts; ++i)
1276  {
1277  PyObject *volatile value;
1278  PLyObToDatum *att;
1279 
1280  if (desc->attrs[i]->attisdropped)
1281  {
1282  values[i] = (Datum) 0;
1283  nulls[i] = true;
1284  continue;
1285  }
1286 
1287  value = NULL;
1288  att = &info->out.r.atts[i];
1289  PG_TRY();
1290  {
1291  value = PySequence_GetItem(sequence, idx);
1292  Assert(value);
1293  if (value == Py_None)
1294  {
1295  values[i] = (Datum) NULL;
1296  nulls[i] = true;
1297  }
1298  else if (value)
1299  {
1300  values[i] = (att->func) (att, -1, value, false);
1301  nulls[i] = false;
1302  }
1303 
1304  Py_XDECREF(value);
1305  value = NULL;
1306  }
1307  PG_CATCH();
1308  {
1309  Py_XDECREF(value);
1310  PG_RE_THROW();
1311  }
1312  PG_END_TRY();
1313 
1314  idx++;
1315  }
1316 
1317  tuple = heap_form_tuple(desc, values, nulls);
1318  result = heap_copy_tuple_as_datum(tuple, desc);
1319  heap_freetuple(tuple);
1320 
1321  pfree(values);
1322  pfree(nulls);
1323 
1324  return result;
1325 }
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:1633
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
int natts
Definition: tupdesc.h:73
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
static struct @121 value
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:163
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:1667
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 1130 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().

1131 {
1132  Datum result;
1133  HeapTuple typeTup;
1134  PLyTypeInfo locinfo;
1136  MemoryContext cxt;
1137 
1138  /* Create a dummy PLyTypeInfo */
1140  "PL/Python temp context",
1142  MemSet(&locinfo, 0, sizeof(PLyTypeInfo));
1143  PLy_typeinfo_init(&locinfo, cxt);
1144 
1145  typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid));
1146  if (!HeapTupleIsValid(typeTup))
1147  elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
1148 
1149  PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup,
1150  exec_ctx->curr_proc->langid,
1151  exec_ctx->curr_proc->trftypes);
1152 
1153  ReleaseSysCache(typeTup);
1154 
1155  result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string, inarray);
1156 
1157  MemoryContextDelete(cxt);
1158 
1159  return result;
1160 }
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:1633
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
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:1117
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:907