PostgreSQL Source Code  git master
plpy_typeio.h File Reference
#include "access/htup.h"
#include "fmgr.h"
#include "plpython.h"
#include "utils/typcache.h"
Include dependency graph for plpy_typeio.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PLyScalarToOb
 
struct  PLyArrayToOb
 
struct  PLyTupleToOb
 
struct  PLyTransformToOb
 
struct  PLyDatumToOb
 
struct  PLyObToScalar
 
struct  PLyObToArray
 
struct  PLyObToTuple
 
struct  PLyObToDomain
 
struct  PLyObToTransform
 
struct  PLyObToDatum
 

Typedefs

typedef struct PLyDatumToOb PLyDatumToOb
 
typedef PyObject *(* PLyDatumToObFunc) (PLyDatumToOb *arg, Datum val)
 
typedef struct PLyScalarToOb PLyScalarToOb
 
typedef struct PLyArrayToOb PLyArrayToOb
 
typedef struct PLyTupleToOb PLyTupleToOb
 
typedef struct PLyTransformToOb PLyTransformToOb
 
typedef struct PLyObToDatum PLyObToDatum
 
typedef Datum(* PLyObToDatumFunc) (PLyObToDatum *arg, PyObject *val, bool *isnull, bool inarray)
 
typedef struct PLyObToScalar PLyObToScalar
 
typedef struct PLyObToArray PLyObToArray
 
typedef struct PLyObToTuple PLyObToTuple
 
typedef struct PLyObToDomain PLyObToDomain
 
typedef struct PLyObToTransform PLyObToTransform
 

Functions

PGDLLEXPORT PyObject * PLy_input_convert (PLyDatumToOb *arg, Datum val)
 
PGDLLEXPORT Datum PLy_output_convert (PLyObToDatum *arg, PyObject *val, bool *isnull)
 
PGDLLEXPORT PyObject * PLy_input_from_tuple (PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
 
PGDLLEXPORT void PLy_input_setup_func (PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, struct PLyProcedure *proc)
 
PGDLLEXPORT void PLy_output_setup_func (PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, struct PLyProcedure *proc)
 
PGDLLEXPORT void PLy_input_setup_tuple (PLyDatumToOb *arg, TupleDesc desc, struct PLyProcedure *proc)
 
PGDLLEXPORT void PLy_output_setup_tuple (PLyObToDatum *arg, TupleDesc desc, struct PLyProcedure *proc)
 
PGDLLEXPORT void PLy_output_setup_record (PLyObToDatum *arg, TupleDesc desc, struct PLyProcedure *proc)
 
PGDLLEXPORT char * PLyObject_AsString (PyObject *plrv)
 

Typedef Documentation

◆ PLyArrayToOb

typedef struct PLyArrayToOb PLyArrayToOb

◆ PLyDatumToOb

typedef struct PLyDatumToOb PLyDatumToOb

Definition at line 1 of file plpy_typeio.h.

◆ PLyDatumToObFunc

typedef PyObject*(* PLyDatumToObFunc) (PLyDatumToOb *arg, Datum val)

Definition at line 28 of file plpy_typeio.h.

◆ PLyObToArray

typedef struct PLyObToArray PLyObToArray

◆ PLyObToDatum

typedef struct PLyObToDatum PLyObToDatum

Definition at line 28 of file plpy_typeio.h.

◆ PLyObToDatumFunc

typedef Datum(* PLyObToDatumFunc) (PLyObToDatum *arg, PyObject *val, bool *isnull, bool inarray)

Definition at line 89 of file plpy_typeio.h.

◆ PLyObToDomain

typedef struct PLyObToDomain PLyObToDomain

◆ PLyObToScalar

typedef struct PLyObToScalar PLyObToScalar

◆ PLyObToTransform

◆ PLyObToTuple

typedef struct PLyObToTuple PLyObToTuple

◆ PLyScalarToOb

typedef struct PLyScalarToOb PLyScalarToOb

◆ PLyTransformToOb

◆ PLyTupleToOb

typedef struct PLyTupleToOb PLyTupleToOb

Function Documentation

◆ PLy_input_convert()

PGDLLEXPORT PyObject* PLy_input_convert ( PLyDatumToOb arg,
Datum  val 
)

Definition at line 81 of file plpy_typeio.c.

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

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

Referenced by PLy_function_build_args().

◆ PLy_input_from_tuple()

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

Definition at line 134 of file plpy_typeio.c.

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

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

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

◆ PLy_input_setup_func()

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

Definition at line 418 of file plpy_typeio.c.

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

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

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

◆ PLy_input_setup_tuple()

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

Definition at line 165 of file plpy_typeio.c.

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

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

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

◆ PLy_output_convert()

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

Definition at line 120 of file plpy_typeio.c.

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

References arg, and val.

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

◆ PLy_output_setup_func()

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

Definition at line 296 of file plpy_typeio.c.

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

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

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

◆ PLy_output_setup_record()

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

Definition at line 261 of file plpy_typeio.c.

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

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

Referenced by PLy_function_build_args().

◆ PLy_output_setup_tuple()

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

Definition at line 215 of file plpy_typeio.c.

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

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

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

◆ PLyObject_AsString()

PGDLLEXPORT char* PLyObject_AsString ( PyObject *  plrv)

Definition at line 1024 of file plpy_typeio.c.

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

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

Referenced by PLyObject_ToScalar(), and PLyUnicode_ToComposite().