PostgreSQL Source Code git master
Loading...
Searching...
No Matches
plpy_typeio.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_typeio.h"
#include "plpy_util.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for plpy_typeio.c:

Go to the source code of this file.

Functions

static PyObjectPLyBool_FromBool (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyFloat_FromFloat4 (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyFloat_FromFloat8 (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyDecimal_FromNumeric (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyLong_FromInt16 (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyLong_FromInt32 (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyLong_FromInt64 (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyLong_FromOid (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyBytes_FromBytea (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyUnicode_FromScalar (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyObject_FromTransform (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyList_FromArray (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyList_FromArray_recurse (PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
 
static PyObjectPLyDict_FromComposite (PLyDatumToOb *arg, Datum d)
 
static PyObjectPLyDict_FromTuple (PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
 
static Datum PLyObject_ToBool (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToBytea (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToComposite (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToScalar (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToDomain (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLyObject_ToTransform (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static Datum PLySequence_ToArray (PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
 
static void PLySequence_ToArray_recurse (PyObject *obj, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, PLyObToDatum *elm, Oid elmbasetype)
 
static Datum PLyUnicode_ToComposite (PLyObToDatum *arg, PyObject *string, bool inarray)
 
static Datum PLyMapping_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
 
static Datum PLySequence_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
 
static Datum PLyGenericObject_ToComposite (PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
 
PyObjectPLy_input_convert (PLyDatumToOb *arg, Datum val)
 
Datum PLy_output_convert (PLyObToDatum *arg, PyObject *val, bool *isnull)
 
PyObjectPLy_input_from_tuple (PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
 
void PLy_input_setup_tuple (PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_tuple (PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_record (PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
 
void PLy_output_setup_func (PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
 
void PLy_input_setup_func (PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
 
charPLyObject_AsString (PyObject *plrv)
 

Function Documentation

◆ PLy_input_convert()

PyObject * PLy_input_convert ( PLyDatumToOb arg,
Datum  val 
)

Definition at line 81 of file plpy_typeio.c.

82{
83 PyObject *result;
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 */
100
102
103 result = arg->func(arg, val);
104
105 MemoryContextSwitchTo(oldcontext);
106
107 return result;
108}
long val
Definition informix.c:689
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
void * arg
PLyExecutionContext * PLy_current_execution_context(void)
Definition plpy_main.c:336
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition plpy_main.c:345
static int fb(int x)

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

Referenced by PLy_function_build_args().

◆ PLy_input_from_tuple()

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

Definition at line 134 of file plpy_typeio.c.

135{
136 PyObject *dict;
139 MemoryContext oldcontext;
140
141 /*
142 * As in PLy_input_convert, do the work in the scratch context.
143 */
145
147
149
150 MemoryContextSwitchTo(oldcontext);
151
152 return dict;
153}
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)

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

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

◆ PLy_input_setup_func()

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

Definition at line 418 of file plpy_typeio.c.

421{
422 TypeCacheEntry *typentry;
423 char typtype;
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 {
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 */
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->array.elm = (PLyDatumToOb *)
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->transform.typtransform, arg_mcxt);
491 }
492 else if (typtype == TYPTYPE_COMPOSITE)
493 {
494 /* Named composite type, or RECORD */
496 /* We'll set up the per-field data later */
497 arg->tuple.recdesc = NULL;
498 arg->tuple.typentry = typentry;
499 arg->tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
500 arg->tuple.atts = NULL;
501 arg->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:
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:
537 getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
538 fmgr_info_cxt(typoutput, &arg->scalar.typfunc, arg_mcxt);
539 break;
540 }
541 }
542}
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:138
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3057
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition lsyscache.c:2270
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
static PyObject * PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
static PyObject * PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
static PyObject * PLyLong_FromInt32(PLyDatumToOb *arg, Datum d)
static PyObject * PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
static PyObject * PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d)
static PyObject * PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
static PyObject * PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
static PyObject * PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
static PyObject * PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
unsigned int Oid
void check_stack_depth(void)
Definition stack_depth.c:95
int32 domainBaseTypmod
Definition typcache.h:116
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:386
#define INVALID_TUPLEDESC_IDENTIFIER
Definition typcache.h:157
#define TYPECACHE_DOMAIN_BASE_INFO
Definition typcache.h:150

References arg, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, fb(), fmgr_info_cxt(), get_transform_fromsql(), getTypeOutputInfo(), INVALID_TUPLEDESC_IDENTIFIER, PLyProcedure::langid, lookup_type_cache(), MemoryContextAllocZero(), PLy_input_setup_func(), 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_func(), PLy_input_setup_tuple(), PLy_procedure_create(), and PLy_spi_execute_fetch_result().

◆ PLy_input_setup_tuple()

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

Definition at line 165 of file plpy_typeio.c.

166{
167 int i;
168
169 /* We should be working on a previously-set-up struct */
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->tuple.recdesc = desc;
175
176 /* (Re)allocate atts array as needed */
177 if (arg->tuple.natts != desc->natts)
178 {
179 if (arg->tuple.atts)
180 pfree(arg->tuple.atts);
181 arg->tuple.natts = desc->natts;
182 arg->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);
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
200 attr->atttypid, attr->atttypmod,
201 proc);
202 }
203}
#define Assert(condition)
Definition c.h:873
int i
Definition isn.c:77
void pfree(void *pointer)
Definition mcxt.c:1616
FormData_pg_attribute * Form_pg_attribute
PLyTupleToOb tuple
Definition plpy_typeio.h:70
PLyDatumToOb * atts
Definition plpy_typeio.h:48
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160

References arg, Assert, PLyTupleToOb::atts, fb(), i, MemoryContextAllocZero(), TupleDescData::natts, pfree(), PLy_input_setup_func(), PLyDict_FromComposite(), PLyDatumToOb::tuple, and TupleDescAttr().

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

◆ PLy_output_convert()

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

Definition at line 120 of file plpy_typeio.c.

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

References arg, and val.

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

◆ PLy_output_setup_func()

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

Definition at line 296 of file plpy_typeio.c.

299{
300 TypeCacheEntry *typentry;
301 char typtype;
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 {
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->domain.domain_info = NULL;
347 /* Recursively set up conversion info for the element type */
348 arg->domain.base = (PLyObToDatum *)
350 PLy_output_setup_func(arg->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->array.elmbasetype = getBaseType(typentry->typelem);
363 /* Recursively set up conversion info for the element type */
364 arg->array.elm = (PLyObToDatum *)
367 typentry->typelem, typmod,
368 proc);
369 }
370 else if ((trfuncid = get_transform_tosql(typeOid,
371 proc->langid,
372 proc->trftypes)))
373 {
375 fmgr_info_cxt(trfuncid, &arg->transform.typtransform, arg_mcxt);
376 }
377 else if (typtype == TYPTYPE_COMPOSITE)
378 {
379 /* Named composite type, or RECORD */
381 /* We'll set up the per-field data later */
382 arg->tuple.recdesc = NULL;
383 arg->tuple.typentry = typentry;
384 arg->tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
385 arg->tuple.atts = NULL;
386 arg->tuple.natts = 0;
387 /* Mark this invalid till needed, too */
388 arg->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->scalar.typioparam);
404 fmgr_info_cxt(typinput, &arg->scalar.typfunc, arg_mcxt);
405 break;
406 }
407 }
408}
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3024
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition lsyscache.c:2292
Oid getBaseType(Oid typid)
Definition lsyscache.c:2671
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
#define InvalidOid

References arg, check_stack_depth(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, fb(), fmgr_info_cxt(), get_transform_tosql(), getBaseType(), getTypeInputInfo(), INVALID_TUPLEDESC_IDENTIFIER, InvalidOid, PLyProcedure::langid, lookup_type_cache(), MemoryContextAllocZero(), PLy_output_setup_func(), 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_func(), PLy_output_setup_tuple(), PLy_procedure_create(), and PLy_spi_prepare().

◆ PLy_output_setup_record()

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

Definition at line 261 of file plpy_typeio.c.

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

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

Referenced by PLy_exec_function().

◆ PLy_output_setup_tuple()

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

Definition at line 215 of file plpy_typeio.c.

216{
217 int i;
218
219 /* We should be working on a previously-set-up struct */
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->tuple.recdesc = desc;
225
226 /* (Re)allocate atts array as needed */
227 if (arg->tuple.natts != desc->natts)
228 {
229 if (arg->tuple.atts)
230 pfree(arg->tuple.atts);
231 arg->tuple.natts = desc->natts;
232 arg->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);
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
250 attr->atttypid, attr->atttypmod,
251 proc);
252 }
253}
PLyObToTuple tuple
PLyObToDatum * atts

References arg, Assert, PLyObToTuple::atts, fb(), i, MemoryContextAllocZero(), TupleDescData::natts, pfree(), PLy_output_setup_func(), PLyObject_ToComposite(), PLyObToDatum::tuple, and TupleDescAttr().

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

◆ PLyBool_FromBool()

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

Definition at line 550 of file plpy_typeio.c.

551{
552 if (DatumGetBool(d))
555}
static bool DatumGetBool(Datum X)
Definition postgres.h:100

References DatumGetBool(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyBytes_FromBytea()

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

Definition at line 628 of file plpy_typeio.c.

629{
631 char *str = VARDATA_ANY(txt);
632 size_t size = VARSIZE_ANY_EXHDR(txt);
633
634 return PyBytes_FromStringAndSize(str, size);
635}
#define DatumGetByteaPP(X)
Definition fmgr.h:292
const char * str
Definition c.h:706
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486

References DatumGetByteaPP, fb(), str, VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by PLy_input_setup_func().

◆ PLyDecimal_FromNumeric()

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

Definition at line 570 of file plpy_typeio.c.

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

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

Referenced by PLy_input_setup_func().

◆ PLyDict_FromComposite()

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

Definition at line 782 of file plpy_typeio.c.

783{
784 PyObject *dict;
786 Oid tupType;
788 TupleDesc tupdesc;
790
792 /* Extract rowtype info and find a tupdesc */
796
797 /* Set up I/O funcs if not done yet */
798 PLy_input_setup_tuple(arg, tupdesc,
799 PLy_current_execution_context()->curr_proc);
800
801 /* Build a temporary HeapTuple control structure */
803 tmptup.t_data = td;
804
805 dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
806
807 ReleaseTupleDesc(tupdesc);
808
809 return dict;
810}
int32_t int32
Definition c.h:542
#define DatumGetHeapTupleHeader(X)
Definition fmgr.h:296
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:219
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1921

References arg, DatumGetHeapTupleHeader, fb(), HeapTupleHeaderGetDatumLength(), HeapTupleHeaderGetTypeId(), HeapTupleHeaderGetTypMod(), lookup_rowtype_tupdesc(), PLy_current_execution_context(), PLy_input_setup_tuple(), PLyDict_FromTuple(), and ReleaseTupleDesc.

Referenced by PLy_input_setup_func(), and PLy_input_setup_tuple().

◆ PLyDict_FromTuple()

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

Definition at line 816 of file plpy_typeio.c.

817{
818 PyObject *volatile dict;
819
820 /* Simple sanity check that desc matches */
821 Assert(desc->natts == arg->tuple.natts);
822
823 dict = PyDict_New();
824 if (dict == NULL)
825 return NULL;
826
827 PG_TRY();
828 {
829 int i;
830
831 for (i = 0; i < arg->tuple.natts; i++)
832 {
834 Form_pg_attribute attr = TupleDescAttr(desc, i);
835 char *key;
836 Datum vattr;
837 bool is_null;
839
840 if (attr->attisdropped)
841 continue;
842
843 if (attr->attgenerated)
844 {
845 /* don't include unless requested */
847 continue;
848 /* never include virtual columns */
849 if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
850 continue;
851 }
852
853 key = NameStr(attr->attname);
854 vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
855
856 if (is_null)
858 else
859 {
860 value = att->func(att, vattr);
863 }
864 }
865 }
866 PG_CATCH();
867 {
869 PG_RE_THROW();
870 }
871 PG_END_TRY();
872
873 return dict;
874}
#define NameStr(name)
Definition c.h:765
#define PG_RE_THROW()
Definition elog.h:405
#define PG_TRY(...)
Definition elog.h:372
#define PG_END_TRY(...)
Definition elog.h:397
#define PG_CATCH(...)
Definition elog.h:382
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static struct @172 value
uint64_t Datum
Definition postgres.h:70

References arg, Assert, PLyTupleToOb::atts, fb(), heap_getattr(), i, NameStr, TupleDescData::natts, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyDatumToOb::tuple, TupleDescAttr(), and value.

Referenced by PLy_input_from_tuple(), and PLyDict_FromComposite().

◆ PLyFloat_FromFloat4()

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

Definition at line 558 of file plpy_typeio.c.

559{
561}
static float4 DatumGetFloat4(Datum X)
Definition postgres.h:461

References DatumGetFloat4(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyFloat_FromFloat8()

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

Definition at line 564 of file plpy_typeio.c.

565{
567}
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:495

References DatumGetFloat8(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyGenericObject_ToComposite()

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

Definition at line 1488 of file plpy_typeio.c.

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

References arg, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, NameStr, TupleDescData::natts, palloc_array, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, TupleDescAttr(), value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyList_FromArray()

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

Definition at line 667 of file plpy_typeio.c.

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

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

Referenced by PLy_input_setup_func().

◆ PLyList_FromArray_recurse()

static PyObject * PLyList_FromArray_recurse ( PLyDatumToOb elm,
int dims,
int  ndim,
int  dim,
char **  dataptr_p,
bits8 **  bitmap_p,
int bitmask_p 
)
static

Definition at line 707 of file plpy_typeio.c.

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

References att_addlength_pointer, att_nominal_alignby, fb(), fetch_att(), PLyDatumToOb::func, i, PLyList_FromArray_recurse(), PLyDatumToOb::typalign, typalign_to_alignby(), PLyDatumToOb::typbyval, and PLyDatumToOb::typlen.

Referenced by PLyList_FromArray(), and PLyList_FromArray_recurse().

◆ PLyLong_FromInt16()

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

Definition at line 604 of file plpy_typeio.c.

605{
607}
static int16 DatumGetInt16(Datum X)
Definition postgres.h:172

References DatumGetInt16(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromInt32()

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

Definition at line 610 of file plpy_typeio.c.

611{
613}
static int32 DatumGetInt32(Datum X)
Definition postgres.h:212

References DatumGetInt32(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromInt64()

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

Definition at line 616 of file plpy_typeio.c.

617{
619}
static int64 DatumGetInt64(Datum X)
Definition postgres.h:413

References DatumGetInt64(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyLong_FromOid()

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

Definition at line 622 of file plpy_typeio.c.

623{
625}
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:252

References DatumGetObjectId(), and fb().

Referenced by PLy_input_setup_func().

◆ PLyMapping_ToComposite()

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

Definition at line 1346 of file plpy_typeio.c.

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

References arg, Assert, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, NameStr, TupleDescData::natts, palloc_array, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, TupleDescAttr(), value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyObject_AsString()

char * PLyObject_AsString ( PyObject plrv)

Definition at line 1028 of file plpy_typeio.c.

1029{
1031 char *plrv_sc;
1032 size_t plen;
1033 size_t slen;
1034
1035 if (PyUnicode_Check(plrv))
1037 else if (PyFloat_Check(plrv))
1038 {
1039 /* use repr() for floats, str() is lossy */
1041
1043 Py_XDECREF(s);
1044 }
1045 else
1046 {
1048
1050 Py_XDECREF(s);
1051 }
1052 if (!plrv_bo)
1053 PLy_elog(ERROR, "could not create string representation of Python object");
1054
1056 plen = PyBytes_Size(plrv_bo);
1057 slen = strlen(plrv_sc);
1058
1060
1061 if (slen < plen)
1062 ereport(ERROR,
1064 errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
1065 else if (slen > plen)
1066 elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
1067 pg_verifymbstr(plrv_sc, slen, false);
1068
1069 return plrv_sc;
1070}
#define elog(elevel,...)
Definition elog.h:226
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition mbutils.c:1559
char * pstrdup(const char *in)
Definition mcxt.c:1781
PyObject * PLyUnicode_Bytes(PyObject *unicode)
Definition plpy_util.c:19

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

◆ PLyObject_FromTransform()

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

Definition at line 655 of file plpy_typeio.c.

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

References arg, DatumGetPointer(), fb(), and FunctionCall1.

Referenced by PLy_input_setup_func().

◆ PLyObject_ToBool()

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

Definition at line 883 of file plpy_typeio.c.

885{
886 if (plrv == Py_None)
887 {
888 *isnull = true;
889 return (Datum) 0;
890 }
891 *isnull = false;
893}
static Datum BoolGetDatum(bool X)
Definition postgres.h:112

References BoolGetDatum(), and fb().

Referenced by PLy_output_setup_func().

◆ PLyObject_ToBytea()

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

Definition at line 901 of file plpy_typeio.c.

903{
904 PyObject *volatile plrv_so = NULL;
905 Datum rv = (Datum) 0;
906
907 if (plrv == Py_None)
908 {
909 *isnull = true;
910 return (Datum) 0;
911 }
912 *isnull = false;
913
915 if (!plrv_so)
916 PLy_elog(ERROR, "could not create bytes representation of Python object");
917
918 PG_TRY();
919 {
921 size_t len = PyBytes_Size(plrv_so);
922 size_t size = len + VARHDRSZ;
923 bytea *result = palloc(size);
924
925 SET_VARSIZE(result, size);
926 memcpy(VARDATA(result), plrv_sc, len);
927 rv = PointerGetDatum(result);
928 }
929 PG_FINALLY();
930 {
932 }
933 PG_END_TRY();
934
935 return rv;
936}
#define VARHDRSZ
Definition c.h:711
#define PG_FINALLY(...)
Definition elog.h:389
void * palloc(Size size)
Definition mcxt.c:1387
const void size_t len
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432

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

Referenced by PLy_output_setup_func().

◆ PLyObject_ToComposite()

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

Definition at line 945 of file plpy_typeio.c.

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

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

Referenced by PLy_output_setup_func(), and PLy_output_setup_tuple().

◆ PLyObject_ToDomain()

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

Definition at line 1103 of file plpy_typeio.c.

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

References arg, PLyObToDomain::base, PLyObToDatum::domain, domain_check(), fb(), and PLyObToDatum::func.

Referenced by PLy_output_setup_func().

◆ PLyObject_ToScalar()

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

Definition at line 1078 of file plpy_typeio.c.

1080{
1081 char *str;
1082
1083 if (plrv == Py_None)
1084 {
1085 *isnull = true;
1086 return (Datum) 0;
1087 }
1088 *isnull = false;
1089
1091
1092 return InputFunctionCall(&arg->scalar.typfunc,
1093 str,
1094 arg->scalar.typioparam,
1095 arg->typmod);
1096}
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition fmgr.c:1531
#define PLyObject_AsString

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

Referenced by PLy_output_setup_func().

◆ PLyObject_ToTransform()

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

Definition at line 1120 of file plpy_typeio.c.

1122{
1123 if (plrv == Py_None)
1124 {
1125 *isnull = true;
1126 return (Datum) 0;
1127 }
1128 *isnull = false;
1129 return FunctionCall1(&arg->transform.typtransform, PointerGetDatum(plrv));
1130}

References arg, fb(), FunctionCall1, and PointerGetDatum().

Referenced by PLy_output_setup_func().

◆ PLySequence_ToArray()

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

Definition at line 1137 of file plpy_typeio.c.

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

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

Referenced by PLy_output_setup_func().

◆ PLySequence_ToArray_recurse()

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

Definition at line 1197 of file plpy_typeio.c.

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

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

Referenced by PLySequence_ToArray(), and PLySequence_ToArray_recurse().

◆ PLySequence_ToComposite()

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

Definition at line 1411 of file plpy_typeio.c.

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

References arg, Assert, PLyObToTuple::atts, ereport, errcode(), errmsg(), ERROR, fb(), heap_copy_tuple_as_datum(), heap_form_tuple(), heap_freetuple(), i, idx(), TupleDescData::natts, palloc_array, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyObToDatum::tuple, TupleDescCompactAttr(), value, and values.

Referenced by PLyObject_ToComposite().

◆ PLyUnicode_FromScalar()

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

Definition at line 642 of file plpy_typeio.c.

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

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

Referenced by PLy_input_setup_func().

◆ PLyUnicode_ToComposite()

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

Definition at line 1285 of file plpy_typeio.c.

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

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

Referenced by PLyObject_ToComposite().