PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plpy_typeio.c
Go to the documentation of this file.
1/*
2 * transforming Datums to Python objects and vice versa
3 *
4 * src/pl/plpython/plpy_typeio.c
5 */
6
7#include "postgres.h"
8
10#include "catalog/pg_type.h"
11#include "funcapi.h"
12#include "mb/pg_wchar.h"
13#include "miscadmin.h"
14#include "plpy_elog.h"
15#include "plpy_main.h"
16#include "plpy_typeio.h"
17#include "plpython.h"
18#include "utils/array.h"
19#include "utils/builtins.h"
20#include "utils/fmgroids.h"
21#include "utils/lsyscache.h"
22#include "utils/memutils.h"
23
24/* conversion from Datums to Python objects */
25static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
26static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
27static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
28static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
29static PyObject *PLyLong_FromInt16(PLyDatumToOb *arg, Datum d);
30static PyObject *PLyLong_FromInt32(PLyDatumToOb *arg, Datum d);
31static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
32static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
33static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
34static PyObject *PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d);
35static PyObject *PLyObject_FromTransform(PLyDatumToOb *arg, Datum d);
36static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
37static PyObject *PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
38 char **dataptr_p, bits8 **bitmap_p, int *bitmask_p);
39static PyObject *PLyDict_FromComposite(PLyDatumToOb *arg, Datum d);
40static PyObject *PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated);
41
42/* conversion from Python objects to Datums */
43static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv,
44 bool *isnull, bool inarray);
45static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
46 bool *isnull, bool inarray);
47static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
48 bool *isnull, bool inarray);
49static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv,
50 bool *isnull, bool inarray);
51static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv,
52 bool *isnull, bool inarray);
53static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv,
54 bool *isnull, bool inarray);
55static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
56 bool *isnull, bool inarray);
57static void PLySequence_ToArray_recurse(PyObject *obj,
58 ArrayBuildState **astatep,
59 int *ndims, int *dims, int cur_depth,
60 PLyObToDatum *elm, Oid elmbasetype);
61
62/* conversion from Python objects to composite Datums */
63static Datum PLyUnicode_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray);
64static Datum PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping);
65static Datum PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence);
66static Datum PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray);
67
68
69/*
70 * Conversion functions. Remember output from Python is input to
71 * PostgreSQL, and vice versa.
72 */
73
74/*
75 * Perform input conversion, given correctly-set-up state information.
76 *
77 * This is the outer-level entry point for any input conversion. Internally,
78 * the conversion functions recurse directly to each other.
79 */
80PyObject *
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}
109
110/*
111 * Perform output conversion, given correctly-set-up state information.
112 *
113 * This is the outer-level entry point for any output conversion. Internally,
114 * the conversion functions recurse directly to each other.
115 *
116 * The result, as well as any cruft generated along the way, are in the
117 * current memory context. Caller is responsible for cleanup.
118 */
119Datum
120PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
121{
122 /* at outer level, we are not considering an array element */
123 return arg->func(arg, val, isnull, false);
124}
125
126/*
127 * Transform a tuple into a Python dict object.
128 *
129 * Note: the tupdesc must match the one used to set up *arg. We could
130 * insist that this function lookup the tupdesc from what is in *arg,
131 * but in practice all callers have the right tupdesc available.
132 */
133PyObject *
134PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
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}
154
155/*
156 * Initialize, or re-initialize, per-column input info for a composite type.
157 *
158 * This is separate from PLy_input_setup_func() because in cases involving
159 * anonymous record types, we need to be passed the tupdesc explicitly.
160 * It's caller's responsibility that the tupdesc has adequate lifespan
161 * in such cases. If the tupdesc is for a named composite or registered
162 * record type, it does not need to be long-lived.
163 */
164void
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->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}
204
205/*
206 * Initialize, or re-initialize, per-column output info for a composite type.
207 *
208 * This is separate from PLy_output_setup_func() because in cases involving
209 * anonymous record types, we need to be passed the tupdesc explicitly.
210 * It's caller's responsibility that the tupdesc has adequate lifespan
211 * in such cases. If the tupdesc is for a named composite or registered
212 * record type, it does not need to be long-lived.
213 */
214void
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->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}
254
255/*
256 * Set up output info for a PL/Python function returning record.
257 *
258 * Note: the given tupdesc is not necessarily long-lived.
259 */
260void
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}
287
288/*
289 * Recursively initialize the PLyObToDatum structure(s) needed to construct
290 * a SQL value of the specified typeOid/typmod from a Python value.
291 * (But note that at this point we may have RECORDOID/-1, ie, an indeterminate
292 * record type.)
293 * proc is used to look up transform functions.
294 */
295void
297 Oid typeOid, int32 typmod,
298 PLyProcedure *proc)
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 {
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 {
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 */
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}
409
410/*
411 * Recursively initialize the PLyDatumToOb structure(s) needed to construct
412 * a Python value from a SQL value of the specified typeOid/typmod.
413 * (But note that at this point we may have RECORDOID/-1, ie, an indeterminate
414 * record type.)
415 * proc is used to look up transform functions.
416 */
417void
419 Oid typeOid, int32 typmod,
420 PLyProcedure *proc)
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 {
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 */
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:
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->u.scalar.typfunc, arg_mcxt);
539 break;
540 }
541 }
542}
543
544
545/*
546 * Special-purpose input converters.
547 */
548
549static PyObject *
551{
552 if (DatumGetBool(d))
553 Py_RETURN_TRUE;
554 Py_RETURN_FALSE;
555}
556
557static PyObject *
559{
560 return PyFloat_FromDouble(DatumGetFloat4(d));
561}
562
563static PyObject *
565{
566 return PyFloat_FromDouble(DatumGetFloat8(d));
567}
568
569static PyObject *
571{
572 static PyObject *decimal_constructor;
573 char *str;
574 PyObject *pyvalue;
575
576 /* Try to import cdecimal. If it doesn't exist, fall back to decimal. */
578 {
579 PyObject *decimal_module;
580
581 decimal_module = PyImport_ImportModule("cdecimal");
582 if (!decimal_module)
583 {
584 PyErr_Clear();
585 decimal_module = PyImport_ImportModule("decimal");
586 }
587 if (!decimal_module)
588 PLy_elog(ERROR, "could not import a module for Decimal constructor");
589
590 decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
592 PLy_elog(ERROR, "no Decimal attribute in module");
593 }
594
596 pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
597 if (!pyvalue)
598 PLy_elog(ERROR, "conversion from numeric to Decimal failed");
599
600 return pyvalue;
601}
602
603static PyObject *
605{
606 return PyLong_FromLong(DatumGetInt16(d));
607}
608
609static PyObject *
611{
612 return PyLong_FromLong(DatumGetInt32(d));
613}
614
615static PyObject *
617{
618 return PyLong_FromLongLong(DatumGetInt64(d));
619}
620
621static PyObject *
623{
624 return PyLong_FromUnsignedLong(DatumGetObjectId(d));
625}
626
627static PyObject *
629{
630 text *txt = DatumGetByteaPP(d);
631 char *str = VARDATA_ANY(txt);
632 size_t size = VARSIZE_ANY_EXHDR(txt);
633
634 return PyBytes_FromStringAndSize(str, size);
635}
636
637
638/*
639 * Generic input conversion using a SQL type's output function.
640 */
641static PyObject *
643{
644 char *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
645 PyObject *r = PLyUnicode_FromString(x);
646
647 pfree(x);
648 return r;
649}
650
651/*
652 * Convert using a from-SQL transform function.
653 */
654static PyObject *
656{
657 Datum t;
658
659 t = FunctionCall1(&arg->u.transform.typtransform, d);
660 return (PyObject *) DatumGetPointer(t);
661}
662
663/*
664 * Convert a SQL array to a Python list.
665 */
666static PyObject *
668{
669 ArrayType *array = DatumGetArrayTypeP(d);
670 PLyDatumToOb *elm = arg->u.array.elm;
671 int ndim;
672 int *dims;
673 char *dataptr;
674 bits8 *bitmap;
675 int bitmask;
676
677 if (ARR_NDIM(array) == 0)
678 return PyList_New(0);
679
680 /* Array dimensions and left bounds */
681 ndim = ARR_NDIM(array);
682 dims = ARR_DIMS(array);
683 Assert(ndim <= MAXDIM);
684
685 /*
686 * We iterate the SQL array in the physical order it's stored in the
687 * datum. For example, for a 3-dimensional array the order of iteration
688 * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0]
689 * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till
690 * [1,m,k], and so on.
691 *
692 * In Python, there are no multi-dimensional lists as such, but they are
693 * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
694 * list of n m-element arrays, each element of which is k-element array.
695 * PLyList_FromArray_recurse() builds the Python list for a single
696 * dimension, and recurses for the next inner dimension.
697 */
698 dataptr = ARR_DATA_PTR(array);
699 bitmap = ARR_NULLBITMAP(array);
700 bitmask = 1;
701
702 return PLyList_FromArray_recurse(elm, dims, ndim, 0,
703 &dataptr, &bitmap, &bitmask);
704}
705
706static PyObject *
707PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
708 char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
709{
710 int i;
711 PyObject *list;
712
713 list = PyList_New(dims[dim]);
714 if (!list)
715 return NULL;
716
717 if (dim < ndim - 1)
718 {
719 /* Outer dimension. Recurse for each inner slice. */
720 for (i = 0; i < dims[dim]; i++)
721 {
722 PyObject *sublist;
723
724 sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
725 dataptr_p, bitmap_p, bitmask_p);
726 PyList_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
739 for (i = 0; i < dims[dim]; i++)
740 {
741 /* checking for NULL */
742 if (bitmap && (*bitmap & bitmask) == 0)
743 {
744 Py_INCREF(Py_None);
745 PyList_SetItem(list, i, Py_None);
746 }
747 else
748 {
749 Datum itemvalue;
750
751 itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
752 PyList_SetItem(list, i, elm->func(elm, itemvalue));
753 dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
754 dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
755 }
756
757 /* advance bitmap pointer if any */
758 if (bitmap)
759 {
760 bitmask <<= 1;
761 if (bitmask == 0x100 /* (1<<8) */ )
762 {
763 bitmap++;
764 bitmask = 1;
765 }
766 }
767 }
768
769 *dataptr_p = dataptr;
770 *bitmap_p = bitmap;
771 *bitmask_p = bitmask;
772 }
773
774 return list;
775}
776
777/*
778 * Convert a composite SQL value to a Python dict.
779 */
780static PyObject *
782{
783 PyObject *dict;
785 Oid tupType;
786 int32 tupTypmod;
787 TupleDesc tupdesc;
788 HeapTupleData tmptup;
789
791 /* Extract rowtype info and find a tupdesc */
792 tupType = HeapTupleHeaderGetTypeId(td);
793 tupTypmod = HeapTupleHeaderGetTypMod(td);
794 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
795
796 /* Set up I/O funcs if not done yet */
797 PLy_input_setup_tuple(arg, tupdesc,
798 PLy_current_execution_context()->curr_proc);
799
800 /* Build a temporary HeapTuple control structure */
802 tmptup.t_data = td;
803
804 dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
805
806 ReleaseTupleDesc(tupdesc);
807
808 return dict;
809}
810
811/*
812 * Transform a tuple into a Python dict object.
813 */
814static PyObject *
815PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
816{
817 PyObject *volatile dict;
818
819 /* Simple sanity check that desc matches */
820 Assert(desc->natts == arg->u.tuple.natts);
821
822 dict = PyDict_New();
823 if (dict == NULL)
824 return NULL;
825
826 PG_TRY();
827 {
828 int i;
829
830 for (i = 0; i < arg->u.tuple.natts; i++)
831 {
832 PLyDatumToOb *att = &arg->u.tuple.atts[i];
833 Form_pg_attribute attr = TupleDescAttr(desc, i);
834 char *key;
835 Datum vattr;
836 bool is_null;
837 PyObject *value;
838
839 if (attr->attisdropped)
840 continue;
841
842 if (attr->attgenerated)
843 {
844 /* don't include unless requested */
845 if (!include_generated)
846 continue;
847 /* never include virtual columns */
848 if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
849 continue;
850 }
851
852 key = NameStr(attr->attname);
853 vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
854
855 if (is_null)
856 PyDict_SetItemString(dict, key, Py_None);
857 else
858 {
859 value = att->func(att, vattr);
860 PyDict_SetItemString(dict, key, value);
861 Py_DECREF(value);
862 }
863 }
864 }
865 PG_CATCH();
866 {
867 Py_DECREF(dict);
868 PG_RE_THROW();
869 }
870 PG_END_TRY();
871
872 return dict;
873}
874
875/*
876 * Convert a Python object to a PostgreSQL bool datum. This can't go
877 * through the generic conversion function, because Python attaches a
878 * Boolean value to everything, more things than the PostgreSQL bool
879 * type can parse.
880 */
881static Datum
883 bool *isnull, bool inarray)
884{
885 if (plrv == Py_None)
886 {
887 *isnull = true;
888 return (Datum) 0;
889 }
890 *isnull = false;
891 return BoolGetDatum(PyObject_IsTrue(plrv));
892}
893
894/*
895 * Convert a Python object to a PostgreSQL bytea datum. This doesn't
896 * go through the generic conversion function to circumvent problems
897 * with embedded nulls. And it's faster this way.
898 */
899static Datum
901 bool *isnull, bool inarray)
902{
903 PyObject *volatile plrv_so = NULL;
904 Datum rv = (Datum) 0;
905
906 if (plrv == Py_None)
907 {
908 *isnull = true;
909 return (Datum) 0;
910 }
911 *isnull = false;
912
913 plrv_so = PyObject_Bytes(plrv);
914 if (!plrv_so)
915 PLy_elog(ERROR, "could not create bytes representation of Python object");
916
917 PG_TRY();
918 {
919 char *plrv_sc = PyBytes_AsString(plrv_so);
920 size_t len = PyBytes_Size(plrv_so);
921 size_t size = len + VARHDRSZ;
922 bytea *result = palloc(size);
923
924 SET_VARSIZE(result, size);
925 memcpy(VARDATA(result), plrv_sc, len);
926 rv = PointerGetDatum(result);
927 }
928 PG_FINALLY();
929 {
930 Py_XDECREF(plrv_so);
931 }
932 PG_END_TRY();
933
934 return rv;
935}
936
937
938/*
939 * Convert a Python object to a composite type. First look up the type's
940 * description, then route the Python object through the conversion function
941 * for obtaining PostgreSQL tuples.
942 */
943static Datum
945 bool *isnull, bool inarray)
946{
947 Datum rv;
948 TupleDesc desc;
949
950 if (plrv == Py_None)
951 {
952 *isnull = true;
953 return (Datum) 0;
954 }
955 *isnull = false;
956
957 /*
958 * The string conversion case doesn't require a tupdesc, nor per-field
959 * conversion data, so just go for it if that's the case to use.
960 */
961 if (PyUnicode_Check(plrv))
962 return PLyUnicode_ToComposite(arg, plrv, inarray);
963
964 /*
965 * If we're dealing with a named composite type, we must look up the
966 * tupdesc every time, to protect against possible changes to the type.
967 * RECORD types can't change between calls; but we must still be willing
968 * to set up the info the first time, if nobody did yet.
969 */
970 if (arg->typoid != RECORDOID)
971 {
972 desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
973 /* We should have the descriptor of the type's typcache entry */
974 Assert(desc == arg->u.tuple.typentry->tupDesc);
975 /* Detect change of descriptor, update cache if needed */
976 if (arg->u.tuple.tupdescid != arg->u.tuple.typentry->tupDesc_identifier)
977 {
979 PLy_current_execution_context()->curr_proc);
980 arg->u.tuple.tupdescid = arg->u.tuple.typentry->tupDesc_identifier;
981 }
982 }
983 else
984 {
985 desc = arg->u.tuple.recdesc;
986 if (desc == NULL)
987 {
988 desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
989 arg->u.tuple.recdesc = desc;
990 }
991 else
992 {
993 /* Pin descriptor to match unpin below */
994 PinTupleDesc(desc);
995 }
996 }
997
998 /* Simple sanity check on our caching */
999 Assert(desc->natts == arg->u.tuple.natts);
1000
1001 /*
1002 * Convert, using the appropriate method depending on the type of the
1003 * supplied Python object.
1004 */
1005 if (PySequence_Check(plrv))
1006 /* composite type as sequence (tuple, list etc) */
1007 rv = PLySequence_ToComposite(arg, desc, plrv);
1008 else if (PyMapping_Check(plrv))
1009 /* composite type as mapping (currently only dict) */
1010 rv = PLyMapping_ToComposite(arg, desc, plrv);
1011 else
1012 /* returned as smth, must provide method __getattr__(name) */
1013 rv = PLyGenericObject_ToComposite(arg, desc, plrv, inarray);
1014
1015 ReleaseTupleDesc(desc);
1016
1017 return rv;
1018}
1019
1020
1021/*
1022 * Convert Python object to C string in server encoding.
1023 *
1024 * Note: this is exported for use by add-on transform modules.
1025 */
1026char *
1027PLyObject_AsString(PyObject *plrv)
1028{
1029 PyObject *plrv_bo;
1030 char *plrv_sc;
1031 size_t plen;
1032 size_t slen;
1033
1034 if (PyUnicode_Check(plrv))
1035 plrv_bo = PLyUnicode_Bytes(plrv);
1036 else if (PyFloat_Check(plrv))
1037 {
1038 /* use repr() for floats, str() is lossy */
1039 PyObject *s = PyObject_Repr(plrv);
1040
1041 plrv_bo = PLyUnicode_Bytes(s);
1042 Py_XDECREF(s);
1043 }
1044 else
1045 {
1046 PyObject *s = PyObject_Str(plrv);
1047
1048 plrv_bo = PLyUnicode_Bytes(s);
1049 Py_XDECREF(s);
1050 }
1051 if (!plrv_bo)
1052 PLy_elog(ERROR, "could not create string representation of Python object");
1053
1054 plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
1055 plen = PyBytes_Size(plrv_bo);
1056 slen = strlen(plrv_sc);
1057
1058 Py_XDECREF(plrv_bo);
1059
1060 if (slen < plen)
1061 ereport(ERROR,
1062 (errcode(ERRCODE_DATATYPE_MISMATCH),
1063 errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
1064 else if (slen > plen)
1065 elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
1066 pg_verifymbstr(plrv_sc, slen, false);
1067
1068 return plrv_sc;
1069}
1070
1071
1072/*
1073 * Generic output conversion function: convert PyObject to cstring and
1074 * cstring into PostgreSQL type.
1075 */
1076static Datum
1078 bool *isnull, bool inarray)
1079{
1080 char *str;
1081
1082 if (plrv == Py_None)
1083 {
1084 *isnull = true;
1085 return (Datum) 0;
1086 }
1087 *isnull = false;
1088
1089 str = PLyObject_AsString(plrv);
1090
1091 return InputFunctionCall(&arg->u.scalar.typfunc,
1092 str,
1093 arg->u.scalar.typioparam,
1094 arg->typmod);
1095}
1096
1097
1098/*
1099 * Convert to a domain type.
1100 */
1101static Datum
1103 bool *isnull, bool inarray)
1104{
1105 Datum result;
1106 PLyObToDatum *base = arg->u.domain.base;
1107
1108 result = base->func(base, plrv, isnull, inarray);
1109 domain_check(result, *isnull, arg->typoid,
1110 &arg->u.domain.domain_info, arg->mcxt);
1111 return result;
1112}
1113
1114
1115/*
1116 * Convert using a to-SQL transform function.
1117 */
1118static Datum
1120 bool *isnull, bool inarray)
1121{
1122 if (plrv == Py_None)
1123 {
1124 *isnull = true;
1125 return (Datum) 0;
1126 }
1127 *isnull = false;
1128 return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
1129}
1130
1131
1132/*
1133 * Convert Python sequence (or list of lists) to SQL array.
1134 */
1135static Datum
1137 bool *isnull, bool inarray)
1138{
1139 ArrayBuildState *astate = NULL;
1140 int ndims = 1;
1141 int dims[MAXDIM];
1142 int lbs[MAXDIM];
1143
1144 if (plrv == Py_None)
1145 {
1146 *isnull = true;
1147 return (Datum) 0;
1148 }
1149 *isnull = false;
1150
1151 /*
1152 * For historical reasons, we allow any sequence (not only a list) at the
1153 * top level when converting a Python object to a SQL array. However, a
1154 * multi-dimensional array is recognized only when the object contains
1155 * true lists.
1156 */
1157 if (!PySequence_Check(plrv))
1158 ereport(ERROR,
1159 (errcode(ERRCODE_DATATYPE_MISMATCH),
1160 errmsg("return value of function with array return type is not a Python sequence")));
1161
1162 /* Initialize dimensionality info with first-level dimension */
1163 memset(dims, 0, sizeof(dims));
1164 dims[0] = PySequence_Length(plrv);
1165
1166 /*
1167 * Traverse the Python lists, in depth-first order, and collect all the
1168 * elements at the bottom level into an ArrayBuildState.
1169 */
1170 PLySequence_ToArray_recurse(plrv, &astate,
1171 &ndims, dims, 1,
1172 arg->u.array.elm,
1173 arg->u.array.elmbasetype);
1174
1175 /* ensure we get zero-D array for no inputs, as per PG convention */
1176 if (astate == NULL)
1177 return PointerGetDatum(construct_empty_array(arg->u.array.elmbasetype));
1178
1179 for (int i = 0; i < ndims; i++)
1180 lbs[i] = 1;
1181
1182 return makeMdArrayResult(astate, ndims, dims, lbs,
1183 CurrentMemoryContext, true);
1184}
1185
1186/*
1187 * Helper function for PLySequence_ToArray. Traverse a Python list of lists in
1188 * depth-first order, storing the elements in *astatep.
1189 *
1190 * The ArrayBuildState is created only when we first find a scalar element;
1191 * if we didn't do it like that, we'd need some other convention for knowing
1192 * whether we'd already found any scalars (and thus the number of dimensions
1193 * is frozen).
1194 */
1195static void
1197 int *ndims, int *dims, int cur_depth,
1198 PLyObToDatum *elm, Oid elmbasetype)
1199{
1200 int i;
1201 int len = PySequence_Length(obj);
1202
1203 /* We should not get here with a non-sequence object */
1204 if (len < 0)
1205 PLy_elog(ERROR, "could not determine sequence length for function return value");
1206
1207 for (i = 0; i < len; i++)
1208 {
1209 /* fetch the array element */
1210 PyObject *subobj = PySequence_GetItem(obj, i);
1211
1212 /* need PG_TRY to ensure we release the subobj's refcount */
1213 PG_TRY();
1214 {
1215 /* multi-dimensional array? */
1216 if (PyList_Check(subobj))
1217 {
1218 /* set size when at first element in this level, else compare */
1219 if (i == 0 && *ndims == cur_depth)
1220 {
1221 /* array after some scalars at same level? */
1222 if (*astatep != NULL)
1223 ereport(ERROR,
1224 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1225 errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1226 /* too many dimensions? */
1227 if (cur_depth >= MAXDIM)
1228 ereport(ERROR,
1229 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1230 errmsg("number of array dimensions exceeds the maximum allowed (%d)",
1231 MAXDIM)));
1232 /* OK, add a dimension */
1233 dims[*ndims] = PySequence_Length(subobj);
1234 (*ndims)++;
1235 }
1236 else if (cur_depth >= *ndims ||
1237 PySequence_Length(subobj) != dims[cur_depth])
1238 ereport(ERROR,
1239 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1240 errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1241
1242 /* recurse to fetch elements of this sub-array */
1243 PLySequence_ToArray_recurse(subobj, astatep,
1244 ndims, dims, cur_depth + 1,
1245 elm, elmbasetype);
1246 }
1247 else
1248 {
1249 Datum dat;
1250 bool isnull;
1251
1252 /* scalar after some sub-arrays at same level? */
1253 if (*ndims != cur_depth)
1254 ereport(ERROR,
1255 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1256 errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1257
1258 /* convert non-list object to Datum */
1259 dat = elm->func(elm, subobj, &isnull, true);
1260
1261 /* create ArrayBuildState if we didn't already */
1262 if (*astatep == NULL)
1263 *astatep = initArrayResult(elmbasetype,
1264 CurrentMemoryContext, true);
1265
1266 /* ... and save the element value in it */
1267 (void) accumArrayResult(*astatep, dat, isnull,
1268 elmbasetype, CurrentMemoryContext);
1269 }
1270 }
1271 PG_FINALLY();
1272 {
1273 Py_XDECREF(subobj);
1274 }
1275 PG_END_TRY();
1276 }
1277}
1278
1279
1280/*
1281 * Convert a Python string to composite, using record_in.
1282 */
1283static Datum
1284PLyUnicode_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray)
1285{
1286 char *str;
1287
1288 /*
1289 * Set up call data for record_in, if we didn't already. (We can't just
1290 * use DirectFunctionCall, because record_in needs a fn_extra field.)
1291 */
1292 if (!OidIsValid(arg->u.tuple.recinfunc.fn_oid))
1293 fmgr_info_cxt(F_RECORD_IN, &arg->u.tuple.recinfunc, arg->mcxt);
1294
1295 str = PLyObject_AsString(string);
1296
1297 /*
1298 * If we are parsing a composite type within an array, and the string
1299 * isn't a valid record literal, there's a high chance that the function
1300 * did something like:
1301 *
1302 * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
1303 * LANGUAGE plpython;
1304 *
1305 * Before PostgreSQL 10, that was interpreted as a single-dimensional
1306 * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
1307 * for multi-dimensional arrays, and it is now interpreted as a
1308 * two-dimensional array, containing two records, 'foo', and 'bar'.
1309 * record_in() will throw an error, because "foo" is not a valid record
1310 * literal.
1311 *
1312 * To make that less confusing to users who are upgrading from older
1313 * versions, try to give a hint in the typical instances of that. If we
1314 * are parsing an array of composite types, and we see a string literal
1315 * that is not a valid record literal, give a hint. We only want to give
1316 * the hint in the narrow case of a malformed string literal, not any
1317 * error from record_in(), so check for that case here specifically.
1318 *
1319 * This check better match the one in record_in(), so that we don't forbid
1320 * literals that are actually valid!
1321 */
1322 if (inarray)
1323 {
1324 char *ptr = str;
1325
1326 /* Allow leading whitespace */
1327 while (*ptr && isspace((unsigned char) *ptr))
1328 ptr++;
1329 if (*ptr++ != '(')
1330 ereport(ERROR,
1331 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1332 errmsg("malformed record literal: \"%s\"", str),
1333 errdetail("Missing left parenthesis."),
1334 errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".")));
1335 }
1336
1337 return InputFunctionCall(&arg->u.tuple.recinfunc,
1338 str,
1339 arg->typoid,
1340 arg->typmod);
1341}
1342
1343
1344static Datum
1346{
1347 Datum result;
1348 HeapTuple tuple;
1349 Datum *values;
1350 bool *nulls;
1351 volatile int i;
1352
1353 Assert(PyMapping_Check(mapping));
1354
1355 /* Build tuple */
1356 values = palloc(sizeof(Datum) * desc->natts);
1357 nulls = palloc(sizeof(bool) * desc->natts);
1358 for (i = 0; i < desc->natts; ++i)
1359 {
1360 char *key;
1361 PyObject *volatile value;
1362 PLyObToDatum *att;
1363 Form_pg_attribute attr = TupleDescAttr(desc, i);
1364
1365 if (attr->attisdropped)
1366 {
1367 values[i] = (Datum) 0;
1368 nulls[i] = true;
1369 continue;
1370 }
1371
1372 key = NameStr(attr->attname);
1373 value = NULL;
1374 att = &arg->u.tuple.atts[i];
1375 PG_TRY();
1376 {
1377 value = PyMapping_GetItemString(mapping, key);
1378 if (!value)
1379 ereport(ERROR,
1380 (errcode(ERRCODE_UNDEFINED_COLUMN),
1381 errmsg("key \"%s\" not found in mapping", key),
1382 errhint("To return null in a column, "
1383 "add the value None to the mapping with the key named after the column.")));
1384
1385 values[i] = att->func(att, value, &nulls[i], false);
1386
1387 Py_XDECREF(value);
1388 value = NULL;
1389 }
1390 PG_CATCH();
1391 {
1392 Py_XDECREF(value);
1393 PG_RE_THROW();
1394 }
1395 PG_END_TRY();
1396 }
1397
1398 tuple = heap_form_tuple(desc, values, nulls);
1399 result = heap_copy_tuple_as_datum(tuple, desc);
1400 heap_freetuple(tuple);
1401
1402 pfree(values);
1403 pfree(nulls);
1404
1405 return result;
1406}
1407
1408
1409static Datum
1411{
1412 Datum result;
1413 HeapTuple tuple;
1414 Datum *values;
1415 bool *nulls;
1416 volatile int idx;
1417 volatile int i;
1418
1419 Assert(PySequence_Check(sequence));
1420
1421 /*
1422 * Check that sequence length is exactly same as PG tuple's. We actually
1423 * can ignore exceeding items or assume missing ones as null but to avoid
1424 * plpython developer's errors we are strict here
1425 */
1426 idx = 0;
1427 for (i = 0; i < desc->natts; i++)
1428 {
1429 if (!TupleDescAttr(desc, i)->attisdropped)
1430 idx++;
1431 }
1432 if (PySequence_Length(sequence) != idx)
1433 ereport(ERROR,
1434 (errcode(ERRCODE_DATATYPE_MISMATCH),
1435 errmsg("length of returned sequence did not match number of columns in row")));
1436
1437 /* Build tuple */
1438 values = palloc(sizeof(Datum) * desc->natts);
1439 nulls = palloc(sizeof(bool) * desc->natts);
1440 idx = 0;
1441 for (i = 0; i < desc->natts; ++i)
1442 {
1443 PyObject *volatile value;
1444 PLyObToDatum *att;
1445
1446 if (TupleDescAttr(desc, i)->attisdropped)
1447 {
1448 values[i] = (Datum) 0;
1449 nulls[i] = true;
1450 continue;
1451 }
1452
1453 value = NULL;
1454 att = &arg->u.tuple.atts[i];
1455 PG_TRY();
1456 {
1457 value = PySequence_GetItem(sequence, idx);
1458 Assert(value);
1459
1460 values[i] = att->func(att, value, &nulls[i], false);
1461
1462 Py_XDECREF(value);
1463 value = NULL;
1464 }
1465 PG_CATCH();
1466 {
1467 Py_XDECREF(value);
1468 PG_RE_THROW();
1469 }
1470 PG_END_TRY();
1471
1472 idx++;
1473 }
1474
1475 tuple = heap_form_tuple(desc, values, nulls);
1476 result = heap_copy_tuple_as_datum(tuple, desc);
1477 heap_freetuple(tuple);
1478
1479 pfree(values);
1480 pfree(nulls);
1481
1482 return result;
1483}
1484
1485
1486static Datum
1487PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
1488{
1489 Datum result;
1490 HeapTuple tuple;
1491 Datum *values;
1492 bool *nulls;
1493 volatile int i;
1494
1495 /* Build tuple */
1496 values = palloc(sizeof(Datum) * desc->natts);
1497 nulls = palloc(sizeof(bool) * desc->natts);
1498 for (i = 0; i < desc->natts; ++i)
1499 {
1500 char *key;
1501 PyObject *volatile value;
1502 PLyObToDatum *att;
1503 Form_pg_attribute attr = TupleDescAttr(desc, i);
1504
1505 if (attr->attisdropped)
1506 {
1507 values[i] = (Datum) 0;
1508 nulls[i] = true;
1509 continue;
1510 }
1511
1512 key = NameStr(attr->attname);
1513 value = NULL;
1514 att = &arg->u.tuple.atts[i];
1515 PG_TRY();
1516 {
1517 value = PyObject_GetAttrString(object, key);
1518 if (!value)
1519 {
1520 /*
1521 * No attribute for this column in the object.
1522 *
1523 * If we are parsing a composite type in an array, a likely
1524 * cause is that the function contained something like "[[123,
1525 * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1526 * array, with a composite type (123, 'foo') in it. But now
1527 * it's interpreted as a two-dimensional array, and we try to
1528 * interpret "123" as the composite type. See also similar
1529 * heuristic in PLyObject_ToScalar().
1530 */
1531 ereport(ERROR,
1532 (errcode(ERRCODE_UNDEFINED_COLUMN),
1533 errmsg("attribute \"%s\" does not exist in Python object", key),
1534 inarray ?
1535 errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".") :
1536 errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1537 }
1538
1539 values[i] = att->func(att, value, &nulls[i], false);
1540
1541 Py_XDECREF(value);
1542 value = NULL;
1543 }
1544 PG_CATCH();
1545 {
1546 Py_XDECREF(value);
1547 PG_RE_THROW();
1548 }
1549 PG_END_TRY();
1550 }
1551
1552 tuple = heap_form_tuple(desc, values, nulls);
1553 result = heap_copy_tuple_as_datum(tuple, desc);
1554 heap_freetuple(tuple);
1555
1556 pfree(values);
1557 pfree(nulls);
1558
1559 return result;
1560}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
#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
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3580
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5452
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define NameStr(name)
Definition: c.h:717
#define VARHDRSZ
Definition: c.h:663
uint8 bits8
Definition: c.h:509
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:346
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define PG_RE_THROW()
Definition: elog.h:404
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:381
#define elog(elevel,...)
Definition: elog.h:225
#define PG_FINALLY(...)
Definition: elog.h:388
#define ereport(elevel,...)
Definition: elog.h:149
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2260
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1530
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:700
Assert(PointerIsAligned(start, uint64))
const char * str
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
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
long val
Definition: informix.c:689
static struct @165 value
int x
Definition: isn.c:75
int i
Definition: isn.c:77
#define PLy_elog
static PyObject * decimal_constructor
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3047
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:3014
Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:2282
Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
Definition: lsyscache.c:2260
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2661
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: mbutils.c:1556
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1294
char * pstrdup(const char *in)
Definition: mcxt.c:2325
void pfree(void *pointer)
Definition: mcxt.c:2150
void * palloc(Size size)
Definition: mcxt.c:1943
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
void * arg
const void size_t len
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:368
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:377
static PyObject * PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:604
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:296
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
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:134
static PyObject * PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:815
static Datum PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
Definition: plpy_typeio.c:1345
static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:882
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:165
PyObject * PLy_input_convert(PLyDatumToOb *arg, Datum val)
Definition: plpy_typeio.c:81
static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:900
char * PLyObject_AsString(PyObject *plrv)
Definition: plpy_typeio.c:1027
static PyObject * PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:781
static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1077
static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1119
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
void PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:261
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 * PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
Definition: plpy_typeio.c:707
static void PLySequence_ToArray_recurse(PyObject *obj, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, PLyObToDatum *elm, Oid elmbasetype)
Definition: plpy_typeio.c:1196
static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:944
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 Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1136
static PyObject * PLyList_FromArray(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:667
static Datum PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
Definition: plpy_typeio.c:1410
static PyObject * PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:628
static Datum PLyUnicode_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray)
Definition: plpy_typeio.c:1284
void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:215
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:120
static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv, bool *isnull, bool inarray)
Definition: plpy_typeio.c:1102
static PyObject * PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
Definition: plpy_typeio.c:570
static Datum PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
Definition: plpy_typeio.c:1487
PyObject * PLyUnicode_Bytes(PyObject *unicode)
Definition: plpy_util.c:20
PyObject * PLyUnicode_FromString(const char *s)
Definition: plpy_util.c:117
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:390
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static float4 DatumGetFloat4(Datum X)
Definition: postgres.h:463
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:247
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:499
static char * DatumGetCString(Datum X)
Definition: postgres.h:340
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:167
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
void check_stack_depth(void)
Definition: stack_depth.c:95
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
PLyDatumToObFunc func
Definition: plpy_typeio.h:59
int32 typmod
Definition: plpy_typeio.h:61
int16 typlen
Definition: plpy_typeio.h:63
PLyObToDatumFunc func
Definition: plpy_typeio.h:132
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
int32 domainBaseTypmod
Definition: typcache.h:116
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:115
Definition: c.h:658
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
#define PinTupleDesc(tupdesc)
Definition: tupdesc.h:213
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:150
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:185
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:53
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1922
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
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317