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