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
9 #include "access/htup_details.h"
10 #include "access/transam.h"
11 #include "catalog/pg_type.h"
12 #include "funcapi.h"
13 #include "mb/pg_wchar.h"
14 #include "parser/parse_type.h"
15 #include "utils/array.h"
16 #include "utils/builtins.h"
17 #include "utils/fmgroids.h"
18 #include "utils/lsyscache.h"
19 #include "utils/memutils.h"
20 #include "utils/numeric.h"
21 #include "utils/syscache.h"
22 #include "utils/typcache.h"
23
24 #include "plpython.h"
25
26 #include "plpy_typeio.h"
27
28 #include "plpy_elog.h"
29 #include "plpy_main.h"
30
31
32 /* I/O function caching */
33 static void PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
34 static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes);
35
36 /* conversion from Datums to Python objects */
37 static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
38 static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
39 static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
40 static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
41 static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
42 static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
43 static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
44 static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
45 static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
46 static PyObject *PLyString_FromDatum(PLyDatumToOb *arg, Datum d);
47 static PyObject *PLyObject_FromTransform(PLyDatumToOb *arg, Datum d);
48 static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
49 static PyObject *PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
50 char **dataptr_p, bits8 **bitmap_p, int *bitmask_p);
51
52 /* conversion from Python objects to Datums */
53 static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
54 static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
55 static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
56 static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
57 static Datum PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
58 static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray);
59 static void PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
60 int *dims, int ndim, int dim,
61 Datum *elems, bool *nulls, int *currelem);
62
63 /* conversion from Python objects to composite Datums (used by triggers and SRFs) */
64 static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray);
65 static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping);
66 static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence);
67 static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray);
68
69 void
PLy_typeinfo_init(PLyTypeInfo * arg,MemoryContext mcxt)70 PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
71 {
72 arg->is_rowtype = -1;
73 arg->in.r.natts = arg->out.r.natts = 0;
74 arg->in.r.atts = NULL;
75 arg->out.r.atts = NULL;
76 arg->typ_relid = InvalidOid;
77 arg->typrel_xmin = InvalidTransactionId;
78 ItemPointerSetInvalid(&arg->typrel_tid);
79 arg->mcxt = mcxt;
80 }
81
82 /*
83 * Conversion functions. Remember output from Python is input to
84 * PostgreSQL, and vice versa.
85 */
86 void
PLy_input_datum_func(PLyTypeInfo * arg,Oid typeOid,HeapTuple typeTup,Oid langid,List * trftypes)87 PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
88 {
89 if (arg->is_rowtype > 0)
90 elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
91 arg->is_rowtype = 0;
92 PLy_input_datum_func2(&(arg->in.d), arg->mcxt, typeOid, typeTup, langid, trftypes);
93 }
94
95 void
PLy_output_datum_func(PLyTypeInfo * arg,HeapTuple typeTup,Oid langid,List * trftypes)96 PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trftypes)
97 {
98 if (arg->is_rowtype > 0)
99 elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
100 arg->is_rowtype = 0;
101 PLy_output_datum_func2(&(arg->out.d), arg->mcxt, typeTup, langid, trftypes);
102 }
103
104 void
PLy_input_tuple_funcs(PLyTypeInfo * arg,TupleDesc desc)105 PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
106 {
107 int i;
108 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
109 MemoryContext oldcxt;
110
111 oldcxt = MemoryContextSwitchTo(arg->mcxt);
112
113 if (arg->is_rowtype == 0)
114 elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
115 arg->is_rowtype = 1;
116
117 if (arg->in.r.natts != desc->natts)
118 {
119 if (arg->in.r.atts)
120 pfree(arg->in.r.atts);
121 arg->in.r.natts = desc->natts;
122 arg->in.r.atts = palloc0(desc->natts * sizeof(PLyDatumToOb));
123 }
124
125 /* Can this be an unnamed tuple? If not, then an Assert would be enough */
126 if (desc->tdtypmod != -1)
127 elog(ERROR, "received unnamed record type as input");
128
129 Assert(OidIsValid(desc->tdtypeid));
130
131 /*
132 * RECORDOID means we got called to create input functions for a tuple
133 * fetched by plpy.execute or for an anonymous record type
134 */
135 if (desc->tdtypeid != RECORDOID)
136 {
137 HeapTuple relTup;
138
139 /* Get the pg_class tuple corresponding to the type of the input */
140 arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
141 relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
142 if (!HeapTupleIsValid(relTup))
143 elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
144
145 /* Remember XMIN and TID for later validation if cache is still OK */
146 arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
147 arg->typrel_tid = relTup->t_self;
148
149 ReleaseSysCache(relTup);
150 }
151
152 for (i = 0; i < desc->natts; i++)
153 {
154 HeapTuple typeTup;
155
156 if (desc->attrs[i]->attisdropped)
157 continue;
158
159 if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
160 continue; /* already set up this entry */
161
162 typeTup = SearchSysCache1(TYPEOID,
163 ObjectIdGetDatum(desc->attrs[i]->atttypid));
164 if (!HeapTupleIsValid(typeTup))
165 elog(ERROR, "cache lookup failed for type %u",
166 desc->attrs[i]->atttypid);
167
168 PLy_input_datum_func2(&(arg->in.r.atts[i]), arg->mcxt,
169 desc->attrs[i]->atttypid,
170 typeTup,
171 exec_ctx->curr_proc->langid,
172 exec_ctx->curr_proc->trftypes);
173
174 ReleaseSysCache(typeTup);
175 }
176
177 MemoryContextSwitchTo(oldcxt);
178 }
179
180 void
PLy_output_tuple_funcs(PLyTypeInfo * arg,TupleDesc desc)181 PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
182 {
183 int i;
184 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
185 MemoryContext oldcxt;
186
187 oldcxt = MemoryContextSwitchTo(arg->mcxt);
188
189 if (arg->is_rowtype == 0)
190 elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
191 arg->is_rowtype = 1;
192
193 if (arg->out.r.natts != desc->natts)
194 {
195 if (arg->out.r.atts)
196 pfree(arg->out.r.atts);
197 arg->out.r.natts = desc->natts;
198 arg->out.r.atts = palloc0(desc->natts * sizeof(PLyObToDatum));
199 }
200
201 Assert(OidIsValid(desc->tdtypeid));
202
203 /*
204 * RECORDOID means we got called to create output functions for an
205 * anonymous record type
206 */
207 if (desc->tdtypeid != RECORDOID)
208 {
209 HeapTuple relTup;
210
211 /* Get the pg_class tuple corresponding to the type of the output */
212 arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
213 relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
214 if (!HeapTupleIsValid(relTup))
215 elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
216
217 /* Remember XMIN and TID for later validation if cache is still OK */
218 arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
219 arg->typrel_tid = relTup->t_self;
220
221 ReleaseSysCache(relTup);
222 }
223
224 for (i = 0; i < desc->natts; i++)
225 {
226 HeapTuple typeTup;
227
228 if (desc->attrs[i]->attisdropped)
229 continue;
230
231 if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
232 continue; /* already set up this entry */
233
234 typeTup = SearchSysCache1(TYPEOID,
235 ObjectIdGetDatum(desc->attrs[i]->atttypid));
236 if (!HeapTupleIsValid(typeTup))
237 elog(ERROR, "cache lookup failed for type %u",
238 desc->attrs[i]->atttypid);
239
240 PLy_output_datum_func2(&(arg->out.r.atts[i]), arg->mcxt, typeTup,
241 exec_ctx->curr_proc->langid,
242 exec_ctx->curr_proc->trftypes);
243
244 ReleaseSysCache(typeTup);
245 }
246
247 MemoryContextSwitchTo(oldcxt);
248 }
249
250 void
PLy_output_record_funcs(PLyTypeInfo * arg,TupleDesc desc)251 PLy_output_record_funcs(PLyTypeInfo *arg, TupleDesc desc)
252 {
253 /*
254 * If the output record functions are already set, we just have to check
255 * if the record descriptor has not changed
256 */
257 if ((arg->is_rowtype == 1) &&
258 (arg->out.d.typmod != -1) &&
259 (arg->out.d.typmod == desc->tdtypmod))
260 return;
261
262 /* bless the record to make it known to the typcache lookup code */
263 BlessTupleDesc(desc);
264 /* save the freshly generated typmod */
265 arg->out.d.typmod = desc->tdtypmod;
266 /* proceed with normal I/O function caching */
267 PLy_output_tuple_funcs(arg, desc);
268
269 /*
270 * it should change is_rowtype to 1, so we won't go through this again
271 * unless the output record description changes
272 */
273 Assert(arg->is_rowtype == 1);
274 }
275
276 /*
277 * Transform a tuple into a Python dict object.
278 */
279 PyObject *
PLyDict_FromTuple(PLyTypeInfo * info,HeapTuple tuple,TupleDesc desc)280 PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
281 {
282 PyObject *volatile dict;
283 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
284 MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
285 MemoryContext oldcontext = CurrentMemoryContext;
286
287 if (info->is_rowtype != 1)
288 elog(ERROR, "PLyTypeInfo structure describes a datum");
289
290 dict = PyDict_New();
291 if (dict == NULL)
292 PLy_elog(ERROR, "could not create new dictionary");
293
294 PG_TRY();
295 {
296 int i;
297
298 /*
299 * Do the work in the scratch context to avoid leaking memory from the
300 * datatype output function calls.
301 */
302 MemoryContextSwitchTo(scratch_context);
303 for (i = 0; i < info->in.r.natts; i++)
304 {
305 char *key;
306 Datum vattr;
307 bool is_null;
308 PyObject *value;
309
310 if (desc->attrs[i]->attisdropped)
311 continue;
312
313 key = NameStr(desc->attrs[i]->attname);
314 vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
315
316 if (is_null || info->in.r.atts[i].func == NULL)
317 PyDict_SetItemString(dict, key, Py_None);
318 else
319 {
320 value = (info->in.r.atts[i].func) (&info->in.r.atts[i], vattr);
321 PyDict_SetItemString(dict, key, value);
322 Py_DECREF(value);
323 }
324 }
325 MemoryContextSwitchTo(oldcontext);
326 MemoryContextReset(scratch_context);
327 }
328 PG_CATCH();
329 {
330 MemoryContextSwitchTo(oldcontext);
331 Py_DECREF(dict);
332 PG_RE_THROW();
333 }
334 PG_END_TRY();
335
336 return dict;
337 }
338
339 /*
340 * Convert a Python object to a composite Datum, using all supported
341 * conversion methods: composite as a string, as a sequence, as a mapping or
342 * as an object that has __getattr__ support.
343 */
344 Datum
PLyObject_ToCompositeDatum(PLyTypeInfo * info,TupleDesc desc,PyObject * plrv,bool inarray)345 PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv, bool inarray)
346 {
347 Datum datum;
348
349 if (PyString_Check(plrv) || PyUnicode_Check(plrv))
350 datum = PLyString_ToComposite(info, desc, plrv, inarray);
351 else if (PySequence_Check(plrv))
352 /* composite type as sequence (tuple, list etc) */
353 datum = PLySequence_ToComposite(info, desc, plrv);
354 else if (PyMapping_Check(plrv))
355 /* composite type as mapping (currently only dict) */
356 datum = PLyMapping_ToComposite(info, desc, plrv);
357 else
358 /* returned as smth, must provide method __getattr__(name) */
359 datum = PLyGenericObject_ToComposite(info, desc, plrv, inarray);
360
361 return datum;
362 }
363
364 static void
PLy_output_datum_func2(PLyObToDatum * arg,MemoryContext arg_mcxt,HeapTuple typeTup,Oid langid,List * trftypes)365 PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
366 {
367 Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
368 Oid element_type;
369 Oid base_type;
370 Oid funcid;
371 MemoryContext oldcxt;
372
373 oldcxt = MemoryContextSwitchTo(arg_mcxt);
374
375 fmgr_info_cxt(typeStruct->typinput, &arg->typfunc, arg_mcxt);
376 arg->typoid = HeapTupleGetOid(typeTup);
377 arg->typmod = -1;
378 arg->typioparam = getTypeIOParam(typeTup);
379 arg->typbyval = typeStruct->typbyval;
380
381 element_type = get_base_element_type(arg->typoid);
382 base_type = getBaseType(element_type ? element_type : arg->typoid);
383
384 /*
385 * Select a conversion function to convert Python objects to PostgreSQL
386 * datums.
387 */
388
389 if ((funcid = get_transform_tosql(base_type, langid, trftypes)))
390 {
391 arg->func = PLyObject_ToTransform;
392 fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
393 }
394 else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
395 {
396 arg->func = PLyObject_ToComposite;
397 }
398 else
399 switch (base_type)
400 {
401 case BOOLOID:
402 arg->func = PLyObject_ToBool;
403 break;
404 case BYTEAOID:
405 arg->func = PLyObject_ToBytea;
406 break;
407 default:
408 arg->func = PLyObject_ToDatum;
409 break;
410 }
411
412 if (element_type)
413 {
414 char dummy_delim;
415 Oid funcid;
416
417 if (type_is_rowtype(element_type))
418 arg->func = PLyObject_ToComposite;
419
420 arg->elm = palloc0(sizeof(*arg->elm));
421 arg->elm->func = arg->func;
422 arg->elm->typtransform = arg->typtransform;
423 arg->func = PLySequence_ToArray;
424
425 arg->elm->typoid = element_type;
426 arg->elm->typmod = -1;
427 get_type_io_data(element_type, IOFunc_input,
428 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
429 &arg->elm->typioparam, &funcid);
430 fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
431 }
432
433 MemoryContextSwitchTo(oldcxt);
434 }
435
436 static void
PLy_input_datum_func2(PLyDatumToOb * arg,MemoryContext arg_mcxt,Oid typeOid,HeapTuple typeTup,Oid langid,List * trftypes)437 PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
438 {
439 Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
440 Oid element_type;
441 Oid base_type;
442 Oid funcid;
443 MemoryContext oldcxt;
444
445 oldcxt = MemoryContextSwitchTo(arg_mcxt);
446
447 /* Get the type's conversion information */
448 fmgr_info_cxt(typeStruct->typoutput, &arg->typfunc, arg_mcxt);
449 arg->typoid = HeapTupleGetOid(typeTup);
450 arg->typmod = -1;
451 arg->typioparam = getTypeIOParam(typeTup);
452 arg->typbyval = typeStruct->typbyval;
453 arg->typlen = typeStruct->typlen;
454 arg->typalign = typeStruct->typalign;
455
456 /* Determine which kind of Python object we will convert to */
457
458 element_type = get_base_element_type(typeOid);
459 base_type = getBaseType(element_type ? element_type : typeOid);
460
461 if ((funcid = get_transform_fromsql(base_type, langid, trftypes)))
462 {
463 arg->func = PLyObject_FromTransform;
464 fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
465 }
466 else
467 switch (base_type)
468 {
469 case BOOLOID:
470 arg->func = PLyBool_FromBool;
471 break;
472 case FLOAT4OID:
473 arg->func = PLyFloat_FromFloat4;
474 break;
475 case FLOAT8OID:
476 arg->func = PLyFloat_FromFloat8;
477 break;
478 case NUMERICOID:
479 arg->func = PLyDecimal_FromNumeric;
480 break;
481 case INT2OID:
482 arg->func = PLyInt_FromInt16;
483 break;
484 case INT4OID:
485 arg->func = PLyInt_FromInt32;
486 break;
487 case INT8OID:
488 arg->func = PLyLong_FromInt64;
489 break;
490 case OIDOID:
491 arg->func = PLyLong_FromOid;
492 break;
493 case BYTEAOID:
494 arg->func = PLyBytes_FromBytea;
495 break;
496 default:
497 arg->func = PLyString_FromDatum;
498 break;
499 }
500
501 if (element_type)
502 {
503 char dummy_delim;
504 Oid funcid;
505
506 arg->elm = palloc0(sizeof(*arg->elm));
507 arg->elm->func = arg->func;
508 arg->elm->typtransform = arg->typtransform;
509 arg->func = PLyList_FromArray;
510 arg->elm->typoid = element_type;
511 arg->elm->typmod = -1;
512 get_type_io_data(element_type, IOFunc_output,
513 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
514 &arg->elm->typioparam, &funcid);
515 fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
516 }
517
518 MemoryContextSwitchTo(oldcxt);
519 }
520
521 static PyObject *
PLyBool_FromBool(PLyDatumToOb * arg,Datum d)522 PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
523 {
524 if (DatumGetBool(d))
525 Py_RETURN_TRUE;
526 Py_RETURN_FALSE;
527 }
528
529 static PyObject *
PLyFloat_FromFloat4(PLyDatumToOb * arg,Datum d)530 PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
531 {
532 return PyFloat_FromDouble(DatumGetFloat4(d));
533 }
534
535 static PyObject *
PLyFloat_FromFloat8(PLyDatumToOb * arg,Datum d)536 PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
537 {
538 return PyFloat_FromDouble(DatumGetFloat8(d));
539 }
540
541 static PyObject *
PLyDecimal_FromNumeric(PLyDatumToOb * arg,Datum d)542 PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
543 {
544 static PyObject *decimal_constructor;
545 char *str;
546 PyObject *pyvalue;
547
548 /* Try to import cdecimal. If it doesn't exist, fall back to decimal. */
549 if (!decimal_constructor)
550 {
551 PyObject *decimal_module;
552
553 decimal_module = PyImport_ImportModule("cdecimal");
554 if (!decimal_module)
555 {
556 PyErr_Clear();
557 decimal_module = PyImport_ImportModule("decimal");
558 }
559 if (!decimal_module)
560 PLy_elog(ERROR, "could not import a module for Decimal constructor");
561
562 decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
563 if (!decimal_constructor)
564 PLy_elog(ERROR, "no Decimal attribute in module");
565 }
566
567 str = DatumGetCString(DirectFunctionCall1(numeric_out, d));
568 pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
569 if (!pyvalue)
570 PLy_elog(ERROR, "conversion from numeric to Decimal failed");
571
572 return pyvalue;
573 }
574
575 static PyObject *
PLyInt_FromInt16(PLyDatumToOb * arg,Datum d)576 PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
577 {
578 return PyInt_FromLong(DatumGetInt16(d));
579 }
580
581 static PyObject *
PLyInt_FromInt32(PLyDatumToOb * arg,Datum d)582 PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
583 {
584 return PyInt_FromLong(DatumGetInt32(d));
585 }
586
587 static PyObject *
PLyLong_FromInt64(PLyDatumToOb * arg,Datum d)588 PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
589 {
590 /* on 32 bit platforms "long" may be too small */
591 if (sizeof(int64) > sizeof(long))
592 return PyLong_FromLongLong(DatumGetInt64(d));
593 else
594 return PyLong_FromLong(DatumGetInt64(d));
595 }
596
597 static PyObject *
PLyLong_FromOid(PLyDatumToOb * arg,Datum d)598 PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
599 {
600 return PyLong_FromUnsignedLong(DatumGetObjectId(d));
601 }
602
603 static PyObject *
PLyBytes_FromBytea(PLyDatumToOb * arg,Datum d)604 PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
605 {
606 text *txt = DatumGetByteaPP(d);
607 char *str = VARDATA_ANY(txt);
608 size_t size = VARSIZE_ANY_EXHDR(txt);
609
610 return PyBytes_FromStringAndSize(str, size);
611 }
612
613 static PyObject *
PLyString_FromDatum(PLyDatumToOb * arg,Datum d)614 PLyString_FromDatum(PLyDatumToOb *arg, Datum d)
615 {
616 char *x = OutputFunctionCall(&arg->typfunc, d);
617 PyObject *r = PyString_FromString(x);
618
619 pfree(x);
620 return r;
621 }
622
623 static PyObject *
PLyObject_FromTransform(PLyDatumToOb * arg,Datum d)624 PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
625 {
626 return (PyObject *) DatumGetPointer(FunctionCall1(&arg->typtransform, d));
627 }
628
629 static PyObject *
PLyList_FromArray(PLyDatumToOb * arg,Datum d)630 PLyList_FromArray(PLyDatumToOb *arg, Datum d)
631 {
632 ArrayType *array = DatumGetArrayTypeP(d);
633 PLyDatumToOb *elm = arg->elm;
634 int ndim;
635 int *dims;
636 char *dataptr;
637 bits8 *bitmap;
638 int bitmask;
639
640 if (ARR_NDIM(array) == 0)
641 return PyList_New(0);
642
643 /* Array dimensions and left bounds */
644 ndim = ARR_NDIM(array);
645 dims = ARR_DIMS(array);
646 Assert(ndim <= MAXDIM);
647
648 /*
649 * We iterate the SQL array in the physical order it's stored in the
650 * datum. For example, for a 3-dimensional array the order of iteration
651 * would be the following: [0,0,0] elements through [0,0,k], then [0,1,0]
652 * through [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till
653 * [1,m,k], and so on.
654 *
655 * In Python, there are no multi-dimensional lists as such, but they are
656 * represented as a list of lists. So a 3-d array of [n,m,k] elements is a
657 * list of n m-element arrays, each element of which is k-element array.
658 * PLyList_FromArray_recurse() builds the Python list for a single
659 * dimension, and recurses for the next inner dimension.
660 */
661 dataptr = ARR_DATA_PTR(array);
662 bitmap = ARR_NULLBITMAP(array);
663 bitmask = 1;
664
665 return PLyList_FromArray_recurse(elm, dims, ndim, 0,
666 &dataptr, &bitmap, &bitmask);
667 }
668
669 static PyObject *
PLyList_FromArray_recurse(PLyDatumToOb * elm,int * dims,int ndim,int dim,char ** dataptr_p,bits8 ** bitmap_p,int * bitmask_p)670 PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
671 char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
672 {
673 int i;
674 PyObject *list;
675
676 list = PyList_New(dims[dim]);
677
678 if (dim < ndim - 1)
679 {
680 /* Outer dimension. Recurse for each inner slice. */
681 for (i = 0; i < dims[dim]; i++)
682 {
683 PyObject *sublist;
684
685 sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
686 dataptr_p, bitmap_p, bitmask_p);
687 PyList_SET_ITEM(list, i, sublist);
688 }
689 }
690 else
691 {
692 /*
693 * Innermost dimension. Fill the list with the values from the array
694 * for this slice.
695 */
696 char *dataptr = *dataptr_p;
697 bits8 *bitmap = *bitmap_p;
698 int bitmask = *bitmask_p;
699
700 for (i = 0; i < dims[dim]; i++)
701 {
702 /* checking for NULL */
703 if (bitmap && (*bitmap & bitmask) == 0)
704 {
705 Py_INCREF(Py_None);
706 PyList_SET_ITEM(list, i, Py_None);
707 }
708 else
709 {
710 Datum itemvalue;
711
712 itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
713 PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
714 dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
715 dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
716 }
717
718 /* advance bitmap pointer if any */
719 if (bitmap)
720 {
721 bitmask <<= 1;
722 if (bitmask == 0x100 /* (1<<8) */ )
723 {
724 bitmap++;
725 bitmask = 1;
726 }
727 }
728 }
729
730 *dataptr_p = dataptr;
731 *bitmap_p = bitmap;
732 *bitmask_p = bitmask;
733 }
734
735 return list;
736 }
737
738 /*
739 * Convert a Python object to a PostgreSQL bool datum. This can't go
740 * through the generic conversion function, because Python attaches a
741 * Boolean value to everything, more things than the PostgreSQL bool
742 * type can parse.
743 */
744 static Datum
PLyObject_ToBool(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)745 PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
746 {
747 Datum rv;
748
749 Assert(plrv != Py_None);
750 rv = BoolGetDatum(PyObject_IsTrue(plrv));
751
752 if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
753 domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
754
755 return rv;
756 }
757
758 /*
759 * Convert a Python object to a PostgreSQL bytea datum. This doesn't
760 * go through the generic conversion function to circumvent problems
761 * with embedded nulls. And it's faster this way.
762 */
763 static Datum
PLyObject_ToBytea(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)764 PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
765 {
766 PyObject *volatile plrv_so = NULL;
767 Datum rv;
768
769 Assert(plrv != Py_None);
770
771 plrv_so = PyObject_Bytes(plrv);
772 if (!plrv_so)
773 PLy_elog(ERROR, "could not create bytes representation of Python object");
774
775 PG_TRY();
776 {
777 char *plrv_sc = PyBytes_AsString(plrv_so);
778 size_t len = PyBytes_Size(plrv_so);
779 size_t size = len + VARHDRSZ;
780 bytea *result = palloc(size);
781
782 SET_VARSIZE(result, size);
783 memcpy(VARDATA(result), plrv_sc, len);
784 rv = PointerGetDatum(result);
785 }
786 PG_CATCH();
787 {
788 Py_XDECREF(plrv_so);
789 PG_RE_THROW();
790 }
791 PG_END_TRY();
792
793 Py_XDECREF(plrv_so);
794
795 if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
796 domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
797
798 return rv;
799 }
800
801
802 /*
803 * Convert a Python object to a composite type. First look up the type's
804 * description, then route the Python object through the conversion function
805 * for obtaining PostgreSQL tuples.
806 */
807 static Datum
PLyObject_ToComposite(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)808 PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
809 {
810 Datum rv;
811 PLyTypeInfo info;
812 TupleDesc desc;
813 MemoryContext cxt;
814
815 if (typmod != -1)
816 elog(ERROR, "received unnamed record type as input");
817
818 /* Create a dummy PLyTypeInfo */
819 cxt = AllocSetContextCreate(CurrentMemoryContext,
820 "PL/Python temp context",
821 ALLOCSET_DEFAULT_SIZES);
822 MemSet(&info, 0, sizeof(PLyTypeInfo));
823 PLy_typeinfo_init(&info, cxt);
824 /* Mark it as needing output routines lookup */
825 info.is_rowtype = 2;
826
827 desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
828
829 /*
830 * This will set up the dummy PLyTypeInfo's output conversion routines,
831 * since we left is_rowtype as 2. A future optimization could be caching
832 * that info instead of looking it up every time a tuple is returned from
833 * the function.
834 */
835 rv = PLyObject_ToCompositeDatum(&info, desc, plrv, inarray);
836
837 ReleaseTupleDesc(desc);
838
839 MemoryContextDelete(cxt);
840
841 return rv;
842 }
843
844
845 /*
846 * Convert Python object to C string in server encoding.
847 */
848 char *
PLyObject_AsString(PyObject * plrv)849 PLyObject_AsString(PyObject *plrv)
850 {
851 PyObject *plrv_bo;
852 char *plrv_sc;
853 size_t plen;
854 size_t slen;
855
856 if (PyUnicode_Check(plrv))
857 plrv_bo = PLyUnicode_Bytes(plrv);
858 else if (PyFloat_Check(plrv))
859 {
860 /* use repr() for floats, str() is lossy */
861 #if PY_MAJOR_VERSION >= 3
862 PyObject *s = PyObject_Repr(plrv);
863
864 plrv_bo = PLyUnicode_Bytes(s);
865 Py_XDECREF(s);
866 #else
867 plrv_bo = PyObject_Repr(plrv);
868 #endif
869 }
870 else
871 {
872 #if PY_MAJOR_VERSION >= 3
873 PyObject *s = PyObject_Str(plrv);
874
875 plrv_bo = PLyUnicode_Bytes(s);
876 Py_XDECREF(s);
877 #else
878 plrv_bo = PyObject_Str(plrv);
879 #endif
880 }
881 if (!plrv_bo)
882 PLy_elog(ERROR, "could not create string representation of Python object");
883
884 plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
885 plen = PyBytes_Size(plrv_bo);
886 slen = strlen(plrv_sc);
887
888 Py_XDECREF(plrv_bo);
889
890 if (slen < plen)
891 ereport(ERROR,
892 (errcode(ERRCODE_DATATYPE_MISMATCH),
893 errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
894 else if (slen > plen)
895 elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
896 pg_verifymbstr(plrv_sc, slen, false);
897
898 return plrv_sc;
899 }
900
901
902 /*
903 * Generic conversion function: Convert PyObject to cstring and
904 * cstring into PostgreSQL type.
905 */
906 static Datum
PLyObject_ToDatum(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)907 PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
908 {
909 char *str;
910
911 Assert(plrv != Py_None);
912
913 str = PLyObject_AsString(plrv);
914
915 /*
916 * If we are parsing a composite type within an array, and the string
917 * isn't a valid record literal, there's a high chance that the function
918 * did something like:
919 *
920 * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
921 * LANGUAGE plpython;
922 *
923 * Before PostgreSQL 10, that was interpreted as a single-dimensional
924 * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
925 * for multi-dimensional arrays, and it is now interpreted as a
926 * two-dimensional array, containing two records, 'foo', and 'bar'.
927 * record_in() will throw an error, because "foo" is not a valid record
928 * literal.
929 *
930 * To make that less confusing to users who are upgrading from older
931 * versions, try to give a hint in the typical instances of that. If we
932 * are parsing an array of composite types, and we see a string literal
933 * that is not a valid record literal, give a hint. We only want to give
934 * the hint in the narrow case of a malformed string literal, not any
935 * error from record_in(), so check for that case here specifically.
936 *
937 * This check better match the one in record_in(), so that we don't forbid
938 * literals that are actually valid!
939 */
940 if (inarray && arg->typfunc.fn_oid == F_RECORD_IN)
941 {
942 char *ptr = str;
943
944 /* Allow leading whitespace */
945 while (*ptr && isspace((unsigned char) *ptr))
946 ptr++;
947 if (*ptr++ != '(')
948 ereport(ERROR,
949 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
950 errmsg("malformed record literal: \"%s\"", str),
951 errdetail("Missing left parenthesis."),
952 errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".")));
953 }
954
955 return InputFunctionCall(&arg->typfunc,
956 str,
957 arg->typioparam,
958 typmod);
959 }
960
961
962 static Datum
PLyObject_ToTransform(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)963 PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
964 {
965 return FunctionCall1(&arg->typtransform, PointerGetDatum(plrv));
966 }
967
968
969 static Datum
PLySequence_ToArray(PLyObToDatum * arg,int32 typmod,PyObject * plrv,bool inarray)970 PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray)
971 {
972 ArrayType *array;
973 int i;
974 Datum *elems;
975 bool *nulls;
976 int64 len;
977 int ndim;
978 int dims[MAXDIM];
979 int lbs[MAXDIM];
980 int currelem;
981 Datum rv;
982 PyObject *pyptr = plrv;
983 PyObject *next;
984
985 Assert(plrv != Py_None);
986
987 /*
988 * Determine the number of dimensions, and their sizes.
989 */
990 ndim = 0;
991 len = 1;
992
993 Py_INCREF(plrv);
994
995 for (;;)
996 {
997 if (!PyList_Check(pyptr))
998 break;
999
1000 if (ndim == MAXDIM)
1001 PLy_elog(ERROR, "number of array dimensions exceeds the maximum allowed (%d)", MAXDIM);
1002
1003 dims[ndim] = PySequence_Length(pyptr);
1004 if (dims[ndim] < 0)
1005 PLy_elog(ERROR, "could not determine sequence length for function return value");
1006
1007 if (dims[ndim] > MaxAllocSize)
1008 PLy_elog(ERROR, "array size exceeds the maximum allowed");
1009
1010 len *= dims[ndim];
1011 if (len > MaxAllocSize)
1012 PLy_elog(ERROR, "array size exceeds the maximum allowed");
1013
1014 if (dims[ndim] == 0)
1015 {
1016 /* empty sequence */
1017 break;
1018 }
1019
1020 ndim++;
1021
1022 next = PySequence_GetItem(pyptr, 0);
1023 Py_XDECREF(pyptr);
1024 pyptr = next;
1025 }
1026 Py_XDECREF(pyptr);
1027
1028 /*
1029 * Check for zero dimensions. This happens if the object is a tuple or a
1030 * string, rather than a list, or is not a sequence at all. We don't map
1031 * tuples or strings to arrays in general, but in the first level, be
1032 * lenient, for historical reasons. So if the object is a sequence of any
1033 * kind, treat it as a one-dimensional array.
1034 */
1035 if (ndim == 0)
1036 {
1037 if (!PySequence_Check(plrv))
1038 PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");
1039
1040 ndim = 1;
1041 len = dims[0] = PySequence_Length(plrv);
1042 }
1043
1044 /*
1045 * Traverse the Python lists, in depth-first order, and collect all the
1046 * elements at the bottom level into 'elems'/'nulls' arrays.
1047 */
1048 elems = palloc(sizeof(Datum) * len);
1049 nulls = palloc(sizeof(bool) * len);
1050 currelem = 0;
1051 PLySequence_ToArray_recurse(arg->elm, plrv,
1052 dims, ndim, 0,
1053 elems, nulls, &currelem);
1054
1055 for (i = 0; i < ndim; i++)
1056 lbs[i] = 1;
1057
1058 array = construct_md_array(elems,
1059 nulls,
1060 ndim,
1061 dims,
1062 lbs,
1063 get_base_element_type(arg->typoid),
1064 arg->elm->typlen,
1065 arg->elm->typbyval,
1066 arg->elm->typalign);
1067
1068 /*
1069 * If the result type is a domain of array, the resulting array must be
1070 * checked.
1071 */
1072 rv = PointerGetDatum(array);
1073 if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
1074 domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
1075 return rv;
1076 }
1077
1078 /*
1079 * Helper function for PLySequence_ToArray. Traverse a Python list of lists in
1080 * depth-first order, storing the elements in 'elems'.
1081 */
1082 static void
PLySequence_ToArray_recurse(PLyObToDatum * elm,PyObject * list,int * dims,int ndim,int dim,Datum * elems,bool * nulls,int * currelem)1083 PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
1084 int *dims, int ndim, int dim,
1085 Datum *elems, bool *nulls, int *currelem)
1086 {
1087 int i;
1088
1089 if (PySequence_Length(list) != dims[dim])
1090 ereport(ERROR,
1091 (errmsg("wrong length of inner sequence: has length %d, but %d was expected",
1092 (int) PySequence_Length(list), dims[dim]),
1093 (errdetail("To construct a multidimensional array, the inner sequences must all have the same length."))));
1094
1095 if (dim < ndim - 1)
1096 {
1097 for (i = 0; i < dims[dim]; i++)
1098 {
1099 PyObject *sublist = PySequence_GetItem(list, i);
1100
1101 PLySequence_ToArray_recurse(elm, sublist, dims, ndim, dim + 1,
1102 elems, nulls, currelem);
1103 Py_XDECREF(sublist);
1104 }
1105 }
1106 else
1107 {
1108 for (i = 0; i < dims[dim]; i++)
1109 {
1110 PyObject *obj = PySequence_GetItem(list, i);
1111
1112 if (obj == Py_None)
1113 {
1114 nulls[*currelem] = true;
1115 elems[*currelem] = (Datum) 0;
1116 }
1117 else
1118 {
1119 nulls[*currelem] = false;
1120 elems[*currelem] = elm->func(elm, -1, obj, true);
1121 }
1122 Py_XDECREF(obj);
1123 (*currelem)++;
1124 }
1125 }
1126 }
1127
1128
1129 static Datum
PLyString_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * string,bool inarray)1130 PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray)
1131 {
1132 Datum result;
1133 HeapTuple typeTup;
1134 PLyTypeInfo locinfo;
1135 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
1136 MemoryContext cxt;
1137
1138 /* Create a dummy PLyTypeInfo */
1139 cxt = AllocSetContextCreate(CurrentMemoryContext,
1140 "PL/Python temp context",
1141 ALLOCSET_DEFAULT_SIZES);
1142 MemSet(&locinfo, 0, sizeof(PLyTypeInfo));
1143 PLy_typeinfo_init(&locinfo, cxt);
1144
1145 typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid));
1146 if (!HeapTupleIsValid(typeTup))
1147 elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
1148
1149 PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup,
1150 exec_ctx->curr_proc->langid,
1151 exec_ctx->curr_proc->trftypes);
1152
1153 ReleaseSysCache(typeTup);
1154
1155 result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string, inarray);
1156
1157 MemoryContextDelete(cxt);
1158
1159 return result;
1160 }
1161
1162
1163 static Datum
PLyMapping_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * mapping)1164 PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
1165 {
1166 Datum result;
1167 HeapTuple tuple;
1168 Datum *values;
1169 bool *nulls;
1170 volatile int i;
1171
1172 Assert(PyMapping_Check(mapping));
1173
1174 if (info->is_rowtype == 2)
1175 PLy_output_tuple_funcs(info, desc);
1176 Assert(info->is_rowtype == 1);
1177
1178 /* Build tuple */
1179 values = palloc(sizeof(Datum) * desc->natts);
1180 nulls = palloc(sizeof(bool) * desc->natts);
1181 for (i = 0; i < desc->natts; ++i)
1182 {
1183 char *key;
1184 PyObject *volatile value;
1185 PLyObToDatum *att;
1186
1187 if (desc->attrs[i]->attisdropped)
1188 {
1189 values[i] = (Datum) 0;
1190 nulls[i] = true;
1191 continue;
1192 }
1193
1194 key = NameStr(desc->attrs[i]->attname);
1195 value = NULL;
1196 att = &info->out.r.atts[i];
1197 PG_TRY();
1198 {
1199 value = PyMapping_GetItemString(mapping, key);
1200 if (value == Py_None)
1201 {
1202 values[i] = (Datum) NULL;
1203 nulls[i] = true;
1204 }
1205 else if (value)
1206 {
1207 values[i] = (att->func) (att, -1, value, false);
1208 nulls[i] = false;
1209 }
1210 else
1211 ereport(ERROR,
1212 (errcode(ERRCODE_UNDEFINED_COLUMN),
1213 errmsg("key \"%s\" not found in mapping", key),
1214 errhint("To return null in a column, "
1215 "add the value None to the mapping with the key named after the column.")));
1216
1217 Py_XDECREF(value);
1218 value = NULL;
1219 }
1220 PG_CATCH();
1221 {
1222 Py_XDECREF(value);
1223 PG_RE_THROW();
1224 }
1225 PG_END_TRY();
1226 }
1227
1228 tuple = heap_form_tuple(desc, values, nulls);
1229 result = heap_copy_tuple_as_datum(tuple, desc);
1230 heap_freetuple(tuple);
1231
1232 pfree(values);
1233 pfree(nulls);
1234
1235 return result;
1236 }
1237
1238
1239 static Datum
PLySequence_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * sequence)1240 PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
1241 {
1242 Datum result;
1243 HeapTuple tuple;
1244 Datum *values;
1245 bool *nulls;
1246 volatile int idx;
1247 volatile int i;
1248
1249 Assert(PySequence_Check(sequence));
1250
1251 /*
1252 * Check that sequence length is exactly same as PG tuple's. We actually
1253 * can ignore exceeding items or assume missing ones as null but to avoid
1254 * plpython developer's errors we are strict here
1255 */
1256 idx = 0;
1257 for (i = 0; i < desc->natts; i++)
1258 {
1259 if (!desc->attrs[i]->attisdropped)
1260 idx++;
1261 }
1262 if (PySequence_Length(sequence) != idx)
1263 ereport(ERROR,
1264 (errcode(ERRCODE_DATATYPE_MISMATCH),
1265 errmsg("length of returned sequence did not match number of columns in row")));
1266
1267 if (info->is_rowtype == 2)
1268 PLy_output_tuple_funcs(info, desc);
1269 Assert(info->is_rowtype == 1);
1270
1271 /* Build tuple */
1272 values = palloc(sizeof(Datum) * desc->natts);
1273 nulls = palloc(sizeof(bool) * desc->natts);
1274 idx = 0;
1275 for (i = 0; i < desc->natts; ++i)
1276 {
1277 PyObject *volatile value;
1278 PLyObToDatum *att;
1279
1280 if (desc->attrs[i]->attisdropped)
1281 {
1282 values[i] = (Datum) 0;
1283 nulls[i] = true;
1284 continue;
1285 }
1286
1287 value = NULL;
1288 att = &info->out.r.atts[i];
1289 PG_TRY();
1290 {
1291 value = PySequence_GetItem(sequence, idx);
1292 Assert(value);
1293 if (value == Py_None)
1294 {
1295 values[i] = (Datum) NULL;
1296 nulls[i] = true;
1297 }
1298 else if (value)
1299 {
1300 values[i] = (att->func) (att, -1, value, false);
1301 nulls[i] = false;
1302 }
1303
1304 Py_XDECREF(value);
1305 value = NULL;
1306 }
1307 PG_CATCH();
1308 {
1309 Py_XDECREF(value);
1310 PG_RE_THROW();
1311 }
1312 PG_END_TRY();
1313
1314 idx++;
1315 }
1316
1317 tuple = heap_form_tuple(desc, values, nulls);
1318 result = heap_copy_tuple_as_datum(tuple, desc);
1319 heap_freetuple(tuple);
1320
1321 pfree(values);
1322 pfree(nulls);
1323
1324 return result;
1325 }
1326
1327
1328 static Datum
PLyGenericObject_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * object,bool inarray)1329 PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray)
1330 {
1331 Datum result;
1332 HeapTuple tuple;
1333 Datum *values;
1334 bool *nulls;
1335 volatile int i;
1336
1337 if (info->is_rowtype == 2)
1338 PLy_output_tuple_funcs(info, desc);
1339 Assert(info->is_rowtype == 1);
1340
1341 /* Build tuple */
1342 values = palloc(sizeof(Datum) * desc->natts);
1343 nulls = palloc(sizeof(bool) * desc->natts);
1344 for (i = 0; i < desc->natts; ++i)
1345 {
1346 char *key;
1347 PyObject *volatile value;
1348 PLyObToDatum *att;
1349
1350 if (desc->attrs[i]->attisdropped)
1351 {
1352 values[i] = (Datum) 0;
1353 nulls[i] = true;
1354 continue;
1355 }
1356
1357 key = NameStr(desc->attrs[i]->attname);
1358 value = NULL;
1359 att = &info->out.r.atts[i];
1360 PG_TRY();
1361 {
1362 value = PyObject_GetAttrString(object, key);
1363 if (value == Py_None)
1364 {
1365 values[i] = (Datum) NULL;
1366 nulls[i] = true;
1367 }
1368 else if (value)
1369 {
1370 values[i] = (att->func) (att, -1, value, false);
1371 nulls[i] = false;
1372 }
1373 else
1374 {
1375 /*
1376 * No attribute for this column in the object.
1377 *
1378 * If we are parsing a composite type in an array, a likely
1379 * cause is that the function contained something like "[[123,
1380 * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1381 * array, with a composite type (123, 'foo') in it. But now
1382 * it's interpreted as a two-dimensional array, and we try to
1383 * interpret "123" as the composite type. See also similar
1384 * heuristic in PLyObject_ToDatum().
1385 */
1386 ereport(ERROR,
1387 (errcode(ERRCODE_UNDEFINED_COLUMN),
1388 errmsg("attribute \"%s\" does not exist in Python object", key),
1389 inarray ?
1390 errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".") :
1391 errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
1392 }
1393
1394 Py_XDECREF(value);
1395 value = NULL;
1396 }
1397 PG_CATCH();
1398 {
1399 Py_XDECREF(value);
1400 PG_RE_THROW();
1401 }
1402 PG_END_TRY();
1403 }
1404
1405 tuple = heap_form_tuple(desc, values, nulls);
1406 result = heap_copy_tuple_as_datum(tuple, desc);
1407 heap_freetuple(tuple);
1408
1409 pfree(values);
1410 pfree(nulls);
1411
1412 return result;
1413 }
1414