Line data Source code
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 "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 */
25 : static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
26 : static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
27 : static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
28 : static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
29 : static PyObject *PLyLong_FromInt16(PLyDatumToOb *arg, Datum d);
30 : static PyObject *PLyLong_FromInt32(PLyDatumToOb *arg, Datum d);
31 : static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
32 : static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
33 : static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
34 : static PyObject *PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d);
35 : static PyObject *PLyObject_FromTransform(PLyDatumToOb *arg, Datum d);
36 : static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
37 : static PyObject *PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
38 : char **dataptr_p, bits8 **bitmap_p, int *bitmask_p);
39 : static PyObject *PLyDict_FromComposite(PLyDatumToOb *arg, Datum d);
40 : static PyObject *PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated);
41 :
42 : /* conversion from Python objects to Datums */
43 : static Datum PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv,
44 : bool *isnull, bool inarray);
45 : static Datum PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
46 : bool *isnull, bool inarray);
47 : static Datum PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
48 : bool *isnull, bool inarray);
49 : static Datum PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv,
50 : bool *isnull, bool inarray);
51 : static Datum PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv,
52 : bool *isnull, bool inarray);
53 : static Datum PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv,
54 : bool *isnull, bool inarray);
55 : static Datum PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
56 : bool *isnull, bool inarray);
57 : static 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 */
63 : static Datum PLyUnicode_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray);
64 : static Datum PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping);
65 : static Datum PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence);
66 : static 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 : */
80 : PyObject *
81 1174 : PLy_input_convert(PLyDatumToOb *arg, Datum val)
82 : {
83 : PyObject *result;
84 1174 : PLyExecutionContext *exec_ctx = PLy_current_execution_context();
85 1174 : 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 1174 : MemoryContextReset(scratch_context);
100 :
101 1174 : oldcontext = MemoryContextSwitchTo(scratch_context);
102 :
103 1174 : result = arg->func(arg, val);
104 :
105 1174 : MemoryContextSwitchTo(oldcontext);
106 :
107 1174 : 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 : */
119 : Datum
120 1136 : PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
121 : {
122 : /* at outer level, we are not considering an array element */
123 1136 : 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 : */
133 : PyObject *
134 398 : PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
135 : {
136 : PyObject *dict;
137 398 : PLyExecutionContext *exec_ctx = PLy_current_execution_context();
138 398 : 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 398 : MemoryContextReset(scratch_context);
145 :
146 398 : oldcontext = MemoryContextSwitchTo(scratch_context);
147 :
148 398 : dict = PLyDict_FromTuple(arg, tuple, desc, include_generated);
149 :
150 398 : MemoryContextSwitchTo(oldcontext);
151 :
152 398 : 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 : */
164 : void
165 378 : PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
166 : {
167 : int i;
168 :
169 : /* We should be working on a previously-set-up struct */
170 : Assert(arg->func == PLyDict_FromComposite);
171 :
172 : /* Save pointer to tupdesc, but only if this is an anonymous record type */
173 378 : if (arg->typoid == RECORDOID && arg->typmod < 0)
174 182 : arg->u.tuple.recdesc = desc;
175 :
176 : /* (Re)allocate atts array as needed */
177 378 : if (arg->u.tuple.natts != desc->natts)
178 : {
179 218 : if (arg->u.tuple.atts)
180 2 : pfree(arg->u.tuple.atts);
181 218 : arg->u.tuple.natts = desc->natts;
182 218 : arg->u.tuple.atts = (PLyDatumToOb *)
183 218 : MemoryContextAllocZero(arg->mcxt,
184 218 : desc->natts * sizeof(PLyDatumToOb));
185 : }
186 :
187 : /* Fill the atts entries, except for dropped columns */
188 1214 : for (i = 0; i < desc->natts; i++)
189 : {
190 836 : Form_pg_attribute attr = TupleDescAttr(desc, i);
191 836 : PLyDatumToOb *att = &arg->u.tuple.atts[i];
192 :
193 836 : if (attr->attisdropped)
194 6 : continue;
195 :
196 830 : if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
197 464 : continue; /* already set up this entry */
198 :
199 366 : PLy_input_setup_func(att, arg->mcxt,
200 : attr->atttypid, attr->atttypmod,
201 : proc);
202 : }
203 378 : }
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 : */
214 : void
215 428 : PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
216 : {
217 : int i;
218 :
219 : /* We should be working on a previously-set-up struct */
220 : Assert(arg->func == PLyObject_ToComposite);
221 :
222 : /* Save pointer to tupdesc, but only if this is an anonymous record type */
223 428 : if (arg->typoid == RECORDOID && arg->typmod < 0)
224 0 : arg->u.tuple.recdesc = desc;
225 :
226 : /* (Re)allocate atts array as needed */
227 428 : if (arg->u.tuple.natts != desc->natts)
228 : {
229 148 : if (arg->u.tuple.atts)
230 6 : pfree(arg->u.tuple.atts);
231 148 : arg->u.tuple.natts = desc->natts;
232 148 : arg->u.tuple.atts = (PLyObToDatum *)
233 148 : MemoryContextAllocZero(arg->mcxt,
234 148 : desc->natts * sizeof(PLyObToDatum));
235 : }
236 :
237 : /* Fill the atts entries, except for dropped columns */
238 1396 : for (i = 0; i < desc->natts; i++)
239 : {
240 968 : Form_pg_attribute attr = TupleDescAttr(desc, i);
241 968 : PLyObToDatum *att = &arg->u.tuple.atts[i];
242 :
243 968 : if (attr->attisdropped)
244 56 : continue;
245 :
246 912 : if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
247 594 : continue; /* already set up this entry */
248 :
249 318 : PLy_output_setup_func(att, arg->mcxt,
250 : attr->atttypid, attr->atttypmod,
251 : proc);
252 : }
253 428 : }
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 : */
260 : void
261 268 : PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
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 268 : 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 268 : arg->typmod = desc->tdtypmod;
280 268 : if (arg->u.tuple.recdesc &&
281 232 : arg->u.tuple.recdesc->tdtypmod != arg->typmod)
282 20 : arg->u.tuple.recdesc = NULL;
283 :
284 : /* Update derived data if necessary */
285 268 : PLy_output_setup_tuple(arg, desc, proc);
286 268 : }
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 : */
295 : void
296 956 : PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt,
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 */
306 956 : check_stack_depth();
307 :
308 956 : arg->typoid = typeOid;
309 956 : arg->typmod = typmod;
310 956 : 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 956 : if (typeOid != RECORDOID)
318 : {
319 920 : typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
320 920 : typtype = typentry->typtype;
321 920 : arg->typbyval = typentry->typbyval;
322 920 : arg->typlen = typentry->typlen;
323 920 : arg->typalign = typentry->typalign;
324 : }
325 : else
326 : {
327 36 : typentry = NULL;
328 36 : typtype = TYPTYPE_COMPOSITE;
329 : /* hard-wired knowledge about type RECORD: */
330 36 : arg->typbyval = false;
331 36 : arg->typlen = -1;
332 36 : 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 956 : if (typtype == TYPTYPE_DOMAIN)
343 : {
344 : /* Domain */
345 28 : arg->func = PLyObject_ToDomain;
346 28 : arg->u.domain.domain_info = NULL;
347 : /* Recursively set up conversion info for the element type */
348 28 : arg->u.domain.base = (PLyObToDatum *)
349 28 : MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
350 28 : PLy_output_setup_func(arg->u.domain.base, arg_mcxt,
351 : typentry->domainBaseType,
352 : typentry->domainBaseTypmod,
353 : proc);
354 : }
355 928 : else if (typentry &&
356 892 : IsTrueArrayType(typentry))
357 : {
358 : /* Standard array */
359 78 : 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 78 : arg->u.array.elmbasetype = getBaseType(typentry->typelem);
363 : /* Recursively set up conversion info for the element type */
364 78 : arg->u.array.elm = (PLyObToDatum *)
365 78 : MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
366 78 : PLy_output_setup_func(arg->u.array.elm, arg_mcxt,
367 : typentry->typelem, typmod,
368 : proc);
369 : }
370 850 : else if ((trfuncid = get_transform_tosql(typeOid,
371 : proc->langid,
372 : proc->trftypes)))
373 : {
374 24 : arg->func = PLyObject_ToTransform;
375 24 : fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
376 : }
377 826 : else if (typtype == TYPTYPE_COMPOSITE)
378 : {
379 : /* Named composite type, or RECORD */
380 146 : arg->func = PLyObject_ToComposite;
381 : /* We'll set up the per-field data later */
382 146 : arg->u.tuple.recdesc = NULL;
383 146 : arg->u.tuple.typentry = typentry;
384 146 : arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
385 146 : arg->u.tuple.atts = NULL;
386 146 : arg->u.tuple.natts = 0;
387 : /* Mark this invalid till needed, too */
388 146 : arg->u.tuple.recinfunc.fn_oid = InvalidOid;
389 : }
390 : else
391 : {
392 : /* Scalar type, but we have a couple of special cases */
393 680 : switch (typeOid)
394 : {
395 28 : case BOOLOID:
396 28 : arg->func = PLyObject_ToBool;
397 28 : break;
398 12 : case BYTEAOID:
399 12 : arg->func = PLyObject_ToBytea;
400 12 : break;
401 640 : default:
402 640 : arg->func = PLyObject_ToScalar;
403 640 : getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam);
404 640 : fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt);
405 640 : break;
406 : }
407 : }
408 956 : }
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 : */
417 : void
418 930 : PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
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 */
429 930 : check_stack_depth();
430 :
431 930 : arg->typoid = typeOid;
432 930 : arg->typmod = typmod;
433 930 : 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 930 : if (typeOid != RECORDOID)
441 : {
442 774 : typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
443 774 : typtype = typentry->typtype;
444 774 : arg->typbyval = typentry->typbyval;
445 774 : arg->typlen = typentry->typlen;
446 774 : arg->typalign = typentry->typalign;
447 : }
448 : else
449 : {
450 156 : typentry = NULL;
451 156 : typtype = TYPTYPE_COMPOSITE;
452 : /* hard-wired knowledge about type RECORD: */
453 156 : arg->typbyval = false;
454 156 : arg->typlen = -1;
455 156 : 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 930 : if (typtype == TYPTYPE_DOMAIN)
466 : {
467 : /* Domain --- we don't care, just recurse down to the base type */
468 18 : PLy_input_setup_func(arg, arg_mcxt,
469 : typentry->domainBaseType,
470 : typentry->domainBaseTypmod,
471 : proc);
472 : }
473 912 : else if (typentry &&
474 756 : IsTrueArrayType(typentry))
475 : {
476 : /* Standard array */
477 26 : arg->func = PLyList_FromArray;
478 : /* Recursively set up conversion info for the element type */
479 26 : arg->u.array.elm = (PLyDatumToOb *)
480 26 : MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb));
481 26 : PLy_input_setup_func(arg->u.array.elm, arg_mcxt,
482 : typentry->typelem, typmod,
483 : proc);
484 : }
485 886 : else if ((trfuncid = get_transform_fromsql(typeOid,
486 : proc->langid,
487 : proc->trftypes)))
488 : {
489 32 : arg->func = PLyObject_FromTransform;
490 32 : fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
491 : }
492 854 : else if (typtype == TYPTYPE_COMPOSITE)
493 : {
494 : /* Named composite type, or RECORD */
495 238 : arg->func = PLyDict_FromComposite;
496 : /* We'll set up the per-field data later */
497 238 : arg->u.tuple.recdesc = NULL;
498 238 : arg->u.tuple.typentry = typentry;
499 238 : arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
500 238 : arg->u.tuple.atts = NULL;
501 238 : arg->u.tuple.natts = 0;
502 : }
503 : else
504 : {
505 : /* Scalar type, but we have a couple of special cases */
506 616 : switch (typeOid)
507 : {
508 28 : case BOOLOID:
509 28 : arg->func = PLyBool_FromBool;
510 28 : break;
511 2 : case FLOAT4OID:
512 2 : arg->func = PLyFloat_FromFloat4;
513 2 : break;
514 2 : case FLOAT8OID:
515 2 : arg->func = PLyFloat_FromFloat8;
516 2 : break;
517 2 : case NUMERICOID:
518 2 : arg->func = PLyDecimal_FromNumeric;
519 2 : break;
520 8 : case INT2OID:
521 8 : arg->func = PLyLong_FromInt16;
522 8 : break;
523 292 : case INT4OID:
524 292 : arg->func = PLyLong_FromInt32;
525 292 : break;
526 10 : case INT8OID:
527 10 : arg->func = PLyLong_FromInt64;
528 10 : break;
529 2 : case OIDOID:
530 2 : arg->func = PLyLong_FromOid;
531 2 : break;
532 14 : case BYTEAOID:
533 14 : arg->func = PLyBytes_FromBytea;
534 14 : break;
535 256 : default:
536 256 : arg->func = PLyUnicode_FromScalar;
537 256 : getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
538 256 : fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
539 256 : break;
540 : }
541 : }
542 930 : }
543 :
544 :
545 : /*
546 : * Special-purpose input converters.
547 : */
548 :
549 : static PyObject *
550 242 : PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
551 : {
552 242 : if (DatumGetBool(d))
553 52 : Py_RETURN_TRUE;
554 190 : Py_RETURN_FALSE;
555 : }
556 :
557 : static PyObject *
558 6 : PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
559 : {
560 6 : return PyFloat_FromDouble(DatumGetFloat4(d));
561 : }
562 :
563 : static PyObject *
564 8 : PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
565 : {
566 8 : return PyFloat_FromDouble(DatumGetFloat8(d));
567 : }
568 :
569 : static PyObject *
570 14 : PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
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. */
577 14 : if (!decimal_constructor)
578 : {
579 : PyObject *decimal_module;
580 :
581 2 : decimal_module = PyImport_ImportModule("cdecimal");
582 2 : if (!decimal_module)
583 : {
584 2 : PyErr_Clear();
585 2 : decimal_module = PyImport_ImportModule("decimal");
586 : }
587 2 : if (!decimal_module)
588 0 : PLy_elog(ERROR, "could not import a module for Decimal constructor");
589 :
590 2 : decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
591 2 : if (!decimal_constructor)
592 0 : PLy_elog(ERROR, "no Decimal attribute in module");
593 : }
594 :
595 14 : str = DatumGetCString(DirectFunctionCall1(numeric_out, d));
596 14 : pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
597 14 : if (!pyvalue)
598 0 : PLy_elog(ERROR, "conversion from numeric to Decimal failed");
599 :
600 14 : return pyvalue;
601 : }
602 :
603 : static PyObject *
604 14 : PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
605 : {
606 14 : return PyLong_FromLong(DatumGetInt16(d));
607 : }
608 :
609 : static PyObject *
610 810 : PLyLong_FromInt32(PLyDatumToOb *arg, Datum d)
611 : {
612 810 : return PyLong_FromLong(DatumGetInt32(d));
613 : }
614 :
615 : static PyObject *
616 30 : PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
617 : {
618 30 : return PyLong_FromLongLong(DatumGetInt64(d));
619 : }
620 :
621 : static PyObject *
622 4 : PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
623 : {
624 4 : return PyLong_FromUnsignedLong(DatumGetObjectId(d));
625 : }
626 :
627 : static PyObject *
628 22 : PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
629 : {
630 22 : text *txt = DatumGetByteaPP(d);
631 22 : char *str = VARDATA_ANY(txt);
632 22 : size_t size = VARSIZE_ANY_EXHDR(txt);
633 :
634 22 : return PyBytes_FromStringAndSize(str, size);
635 : }
636 :
637 :
638 : /*
639 : * Generic input conversion using a SQL type's output function.
640 : */
641 : static PyObject *
642 968 : PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d)
643 : {
644 968 : char *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
645 968 : PyObject *r = PLyUnicode_FromString(x);
646 :
647 968 : pfree(x);
648 968 : return r;
649 : }
650 :
651 : /*
652 : * Convert using a from-SQL transform function.
653 : */
654 : static PyObject *
655 70 : PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
656 : {
657 : Datum t;
658 :
659 70 : t = FunctionCall1(&arg->u.transform.typtransform, d);
660 70 : return (PyObject *) DatumGetPointer(t);
661 : }
662 :
663 : /*
664 : * Convert a SQL array to a Python list.
665 : */
666 : static PyObject *
667 42 : PLyList_FromArray(PLyDatumToOb *arg, Datum d)
668 : {
669 42 : ArrayType *array = DatumGetArrayTypeP(d);
670 42 : PLyDatumToOb *elm = arg->u.array.elm;
671 : int ndim;
672 : int *dims;
673 : char *dataptr;
674 : bits8 *bitmap;
675 : int bitmask;
676 :
677 42 : if (ARR_NDIM(array) == 0)
678 2 : return PyList_New(0);
679 :
680 : /* Array dimensions and left bounds */
681 40 : ndim = ARR_NDIM(array);
682 40 : 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 40 : dataptr = ARR_DATA_PTR(array);
699 40 : bitmap = ARR_NULLBITMAP(array);
700 40 : bitmask = 1;
701 :
702 40 : return PLyList_FromArray_recurse(elm, dims, ndim, 0,
703 : &dataptr, &bitmap, &bitmask);
704 : }
705 :
706 : static PyObject *
707 96 : PLyList_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 96 : list = PyList_New(dims[dim]);
714 96 : if (!list)
715 0 : return NULL;
716 :
717 96 : if (dim < ndim - 1)
718 : {
719 : /* Outer dimension. Recurse for each inner slice. */
720 84 : for (i = 0; i < dims[dim]; i++)
721 : {
722 : PyObject *sublist;
723 :
724 56 : sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
725 : dataptr_p, bitmap_p, bitmask_p);
726 56 : PyList_SET_ITEM(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 68 : char *dataptr = *dataptr_p;
736 68 : bits8 *bitmap = *bitmap_p;
737 68 : int bitmask = *bitmask_p;
738 :
739 240 : for (i = 0; i < dims[dim]; i++)
740 : {
741 : /* checking for NULL */
742 172 : if (bitmap && (*bitmap & bitmask) == 0)
743 : {
744 28 : Py_INCREF(Py_None);
745 28 : PyList_SET_ITEM(list, i, Py_None);
746 : }
747 : else
748 : {
749 : Datum itemvalue;
750 :
751 144 : itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
752 144 : PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
753 144 : dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
754 144 : dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
755 : }
756 :
757 : /* advance bitmap pointer if any */
758 172 : if (bitmap)
759 : {
760 104 : bitmask <<= 1;
761 104 : if (bitmask == 0x100 /* (1<<8) */ )
762 : {
763 8 : bitmap++;
764 8 : bitmask = 1;
765 : }
766 : }
767 : }
768 :
769 68 : *dataptr_p = dataptr;
770 68 : *bitmap_p = bitmap;
771 68 : *bitmask_p = bitmask;
772 : }
773 :
774 96 : return list;
775 : }
776 :
777 : /*
778 : * Convert a composite SQL value to a Python dict.
779 : */
780 : static PyObject *
781 98 : PLyDict_FromComposite(PLyDatumToOb *arg, Datum d)
782 : {
783 : PyObject *dict;
784 : HeapTupleHeader td;
785 : Oid tupType;
786 : int32 tupTypmod;
787 : TupleDesc tupdesc;
788 : HeapTupleData tmptup;
789 :
790 98 : td = DatumGetHeapTupleHeader(d);
791 : /* Extract rowtype info and find a tupdesc */
792 98 : tupType = HeapTupleHeaderGetTypeId(td);
793 98 : tupTypmod = HeapTupleHeaderGetTypMod(td);
794 98 : tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
795 :
796 : /* Set up I/O funcs if not done yet */
797 98 : PLy_input_setup_tuple(arg, tupdesc,
798 98 : PLy_current_execution_context()->curr_proc);
799 :
800 : /* Build a temporary HeapTuple control structure */
801 98 : tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
802 98 : tmptup.t_data = td;
803 :
804 98 : dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
805 :
806 98 : ReleaseTupleDesc(tupdesc);
807 :
808 98 : return dict;
809 : }
810 :
811 : /*
812 : * Transform a tuple into a Python dict object.
813 : */
814 : static PyObject *
815 496 : PLyDict_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 496 : dict = PyDict_New();
823 496 : if (dict == NULL)
824 0 : return NULL;
825 :
826 496 : PG_TRY();
827 : {
828 : int i;
829 :
830 1562 : for (i = 0; i < arg->u.tuple.natts; i++)
831 : {
832 1066 : PLyDatumToOb *att = &arg->u.tuple.atts[i];
833 1066 : Form_pg_attribute attr = TupleDescAttr(desc, i);
834 : char *key;
835 : Datum vattr;
836 : bool is_null;
837 : PyObject *value;
838 :
839 1066 : if (attr->attisdropped)
840 30 : continue;
841 :
842 1060 : if (attr->attgenerated)
843 : {
844 : /* don't include unless requested */
845 36 : if (!include_generated)
846 12 : continue;
847 : /* never include virtual columns */
848 24 : if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
849 12 : continue;
850 : }
851 :
852 1036 : key = NameStr(attr->attname);
853 1036 : vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
854 :
855 1036 : if (is_null)
856 26 : PyDict_SetItemString(dict, key, Py_None);
857 : else
858 : {
859 1010 : value = att->func(att, vattr);
860 1010 : PyDict_SetItemString(dict, key, value);
861 1010 : Py_DECREF(value);
862 : }
863 : }
864 : }
865 0 : PG_CATCH();
866 : {
867 0 : Py_DECREF(dict);
868 0 : PG_RE_THROW();
869 : }
870 496 : PG_END_TRY();
871 :
872 496 : 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 : */
881 : static Datum
882 46 : PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv,
883 : bool *isnull, bool inarray)
884 : {
885 46 : if (plrv == Py_None)
886 : {
887 2 : *isnull = true;
888 2 : return (Datum) 0;
889 : }
890 44 : *isnull = false;
891 44 : 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 : */
899 : static Datum
900 22 : PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
901 : bool *isnull, bool inarray)
902 : {
903 22 : PyObject *volatile plrv_so = NULL;
904 22 : Datum rv = (Datum) 0;
905 :
906 22 : if (plrv == Py_None)
907 : {
908 6 : *isnull = true;
909 6 : return (Datum) 0;
910 : }
911 16 : *isnull = false;
912 :
913 16 : plrv_so = PyObject_Bytes(plrv);
914 16 : if (!plrv_so)
915 0 : PLy_elog(ERROR, "could not create bytes representation of Python object");
916 :
917 16 : PG_TRY();
918 : {
919 16 : char *plrv_sc = PyBytes_AsString(plrv_so);
920 16 : size_t len = PyBytes_Size(plrv_so);
921 16 : size_t size = len + VARHDRSZ;
922 16 : bytea *result = palloc(size);
923 :
924 16 : SET_VARSIZE(result, size);
925 16 : memcpy(VARDATA(result), plrv_sc, len);
926 16 : rv = PointerGetDatum(result);
927 : }
928 0 : PG_FINALLY();
929 : {
930 16 : Py_XDECREF(plrv_so);
931 : }
932 16 : PG_END_TRY();
933 :
934 16 : 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 : */
943 : static Datum
944 582 : PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
945 : bool *isnull, bool inarray)
946 : {
947 : Datum rv;
948 : TupleDesc desc;
949 :
950 582 : if (plrv == Py_None)
951 : {
952 42 : *isnull = true;
953 42 : return (Datum) 0;
954 : }
955 540 : *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 540 : if (PyUnicode_Check(plrv))
962 36 : 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 504 : if (arg->typoid != RECORDOID)
971 : {
972 250 : 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 250 : if (arg->u.tuple.tupdescid != arg->u.tuple.typentry->tupDesc_identifier)
977 : {
978 62 : PLy_output_setup_tuple(arg, desc,
979 62 : PLy_current_execution_context()->curr_proc);
980 62 : arg->u.tuple.tupdescid = arg->u.tuple.typentry->tupDesc_identifier;
981 : }
982 : }
983 : else
984 : {
985 254 : desc = arg->u.tuple.recdesc;
986 254 : if (desc == NULL)
987 : {
988 56 : desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
989 56 : arg->u.tuple.recdesc = desc;
990 : }
991 : else
992 : {
993 : /* Pin descriptor to match unpin below */
994 198 : 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 504 : if (PySequence_Check(plrv))
1006 : /* composite type as sequence (tuple, list etc) */
1007 264 : rv = PLySequence_ToComposite(arg, desc, plrv);
1008 240 : else if (PyMapping_Check(plrv))
1009 : /* composite type as mapping (currently only dict) */
1010 190 : rv = PLyMapping_ToComposite(arg, desc, plrv);
1011 : else
1012 : /* returned as smth, must provide method __getattr__(name) */
1013 50 : rv = PLyGenericObject_ToComposite(arg, desc, plrv, inarray);
1014 :
1015 486 : ReleaseTupleDesc(desc);
1016 :
1017 486 : 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 : */
1026 : char *
1027 3162 : PLyObject_AsString(PyObject *plrv)
1028 : {
1029 : PyObject *plrv_bo;
1030 : char *plrv_sc;
1031 : size_t plen;
1032 : size_t slen;
1033 :
1034 3162 : if (PyUnicode_Check(plrv))
1035 676 : plrv_bo = PLyUnicode_Bytes(plrv);
1036 2486 : else if (PyFloat_Check(plrv))
1037 14 : {
1038 : /* use repr() for floats, str() is lossy */
1039 14 : PyObject *s = PyObject_Repr(plrv);
1040 :
1041 14 : plrv_bo = PLyUnicode_Bytes(s);
1042 14 : Py_XDECREF(s);
1043 : }
1044 : else
1045 : {
1046 2472 : PyObject *s = PyObject_Str(plrv);
1047 :
1048 2472 : plrv_bo = PLyUnicode_Bytes(s);
1049 2472 : Py_XDECREF(s);
1050 : }
1051 3162 : if (!plrv_bo)
1052 0 : PLy_elog(ERROR, "could not create string representation of Python object");
1053 :
1054 3162 : plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
1055 3162 : plen = PyBytes_Size(plrv_bo);
1056 3162 : slen = strlen(plrv_sc);
1057 :
1058 3162 : Py_XDECREF(plrv_bo);
1059 :
1060 3162 : if (slen < plen)
1061 0 : 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 3162 : else if (slen > plen)
1065 0 : elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
1066 3162 : pg_verifymbstr(plrv_sc, slen, false);
1067 :
1068 3162 : return plrv_sc;
1069 : }
1070 :
1071 :
1072 : /*
1073 : * Generic output conversion function: convert PyObject to cstring and
1074 : * cstring into PostgreSQL type.
1075 : */
1076 : static Datum
1077 3198 : PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv,
1078 : bool *isnull, bool inarray)
1079 : {
1080 : char *str;
1081 :
1082 3198 : if (plrv == Py_None)
1083 : {
1084 194 : *isnull = true;
1085 194 : return (Datum) 0;
1086 : }
1087 3004 : *isnull = false;
1088 :
1089 3004 : str = PLyObject_AsString(plrv);
1090 :
1091 3004 : 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 : */
1101 : static Datum
1102 58 : PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv,
1103 : bool *isnull, bool inarray)
1104 : {
1105 : Datum result;
1106 58 : PLyObToDatum *base = arg->u.domain.base;
1107 :
1108 58 : result = base->func(base, plrv, isnull, inarray);
1109 54 : domain_check(result, *isnull, arg->typoid,
1110 : &arg->u.domain.domain_info, arg->mcxt);
1111 32 : return result;
1112 : }
1113 :
1114 :
1115 : /*
1116 : * Convert using a to-SQL transform function.
1117 : */
1118 : static Datum
1119 62 : PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv,
1120 : bool *isnull, bool inarray)
1121 : {
1122 62 : if (plrv == Py_None)
1123 : {
1124 2 : *isnull = true;
1125 2 : return (Datum) 0;
1126 : }
1127 60 : *isnull = false;
1128 60 : return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
1129 : }
1130 :
1131 :
1132 : /*
1133 : * Convert Python sequence (or list of lists) to SQL array.
1134 : */
1135 : static Datum
1136 116 : PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
1137 : bool *isnull, bool inarray)
1138 : {
1139 116 : ArrayBuildState *astate = NULL;
1140 116 : int ndims = 1;
1141 : int dims[MAXDIM];
1142 : int lbs[MAXDIM];
1143 :
1144 116 : if (plrv == Py_None)
1145 : {
1146 4 : *isnull = true;
1147 4 : return (Datum) 0;
1148 : }
1149 112 : *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 112 : if (!PySequence_Check(plrv))
1158 6 : 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 106 : memset(dims, 0, sizeof(dims));
1164 106 : 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 106 : 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 78 : if (astate == NULL)
1177 4 : return PointerGetDatum(construct_empty_array(arg->u.array.elmbasetype));
1178 :
1179 196 : for (int i = 0; i < ndims; i++)
1180 122 : lbs[i] = 1;
1181 :
1182 74 : 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 : */
1195 : static void
1196 510 : PLySequence_ToArray_recurse(PyObject *obj, ArrayBuildState **astatep,
1197 : int *ndims, int *dims, int cur_depth,
1198 : PLyObToDatum *elm, Oid elmbasetype)
1199 : {
1200 : int i;
1201 510 : int len = PySequence_Length(obj);
1202 :
1203 : /* We should not get here with a non-sequence object */
1204 510 : if (len < 0)
1205 0 : PLy_elog(ERROR, "could not determine sequence length for function return value");
1206 :
1207 2716 : for (i = 0; i < len; i++)
1208 : {
1209 : /* fetch the array element */
1210 2252 : PyObject *subobj = PySequence_GetItem(obj, i);
1211 :
1212 : /* need PG_TRY to ensure we release the subobj's refcount */
1213 2252 : PG_TRY();
1214 : {
1215 : /* multi-dimensional array? */
1216 2252 : if (PyList_Check(subobj))
1217 : {
1218 : /* set size when at first element in this level, else compare */
1219 416 : if (i == 0 && *ndims == cur_depth)
1220 : {
1221 : /* array after some scalars at same level? */
1222 80 : if (*astatep != NULL)
1223 2 : ereport(ERROR,
1224 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1225 : errmsg("multidimensional arrays must have array expressions with matching dimensions")));
1226 : /* too many dimensions? */
1227 78 : if (cur_depth >= MAXDIM)
1228 2 : 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 76 : dims[*ndims] = PySequence_Length(subobj);
1234 76 : (*ndims)++;
1235 : }
1236 336 : else if (cur_depth >= *ndims ||
1237 332 : PySequence_Length(subobj) != dims[cur_depth])
1238 8 : 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 404 : 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 1836 : if (*ndims != cur_depth)
1254 4 : 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 1832 : dat = elm->func(elm, subobj, &isnull, true);
1260 :
1261 : /* create ArrayBuildState if we didn't already */
1262 1820 : if (*astatep == NULL)
1263 86 : *astatep = initArrayResult(elmbasetype,
1264 : CurrentMemoryContext, true);
1265 :
1266 : /* ... and save the element value in it */
1267 1820 : (void) accumArrayResult(*astatep, dat, isnull,
1268 : elmbasetype, CurrentMemoryContext);
1269 : }
1270 : }
1271 46 : PG_FINALLY();
1272 : {
1273 2252 : Py_XDECREF(subobj);
1274 : }
1275 2252 : PG_END_TRY();
1276 : }
1277 464 : }
1278 :
1279 :
1280 : /*
1281 : * Convert a Python string to composite, using record_in.
1282 : */
1283 : static Datum
1284 36 : PLyUnicode_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 36 : if (!OidIsValid(arg->u.tuple.recinfunc.fn_oid))
1293 10 : fmgr_info_cxt(F_RECORD_IN, &arg->u.tuple.recinfunc, arg->mcxt);
1294 :
1295 36 : 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 36 : if (inarray)
1323 : {
1324 2 : char *ptr = str;
1325 :
1326 : /* Allow leading whitespace */
1327 2 : while (*ptr && isspace((unsigned char) *ptr))
1328 0 : ptr++;
1329 2 : if (*ptr++ != '(')
1330 2 : 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 34 : return InputFunctionCall(&arg->u.tuple.recinfunc,
1338 : str,
1339 : arg->typoid,
1340 : arg->typmod);
1341 : }
1342 :
1343 :
1344 : static Datum
1345 190 : PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
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 190 : values = palloc(sizeof(Datum) * desc->natts);
1357 190 : nulls = palloc(sizeof(bool) * desc->natts);
1358 730 : for (i = 0; i < desc->natts; ++i)
1359 : {
1360 : char *key;
1361 : PyObject *volatile value;
1362 : PLyObToDatum *att;
1363 546 : Form_pg_attribute attr = TupleDescAttr(desc, i);
1364 :
1365 546 : if (attr->attisdropped)
1366 : {
1367 94 : values[i] = (Datum) 0;
1368 94 : nulls[i] = true;
1369 94 : continue;
1370 : }
1371 :
1372 452 : key = NameStr(attr->attname);
1373 452 : value = NULL;
1374 452 : att = &arg->u.tuple.atts[i];
1375 452 : PG_TRY();
1376 : {
1377 452 : value = PyMapping_GetItemString(mapping, key);
1378 452 : if (!value)
1379 4 : 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 448 : values[i] = att->func(att, value, &nulls[i], false);
1386 :
1387 446 : Py_XDECREF(value);
1388 446 : value = NULL;
1389 : }
1390 6 : PG_CATCH();
1391 : {
1392 6 : Py_XDECREF(value);
1393 6 : PG_RE_THROW();
1394 : }
1395 446 : PG_END_TRY();
1396 : }
1397 :
1398 184 : tuple = heap_form_tuple(desc, values, nulls);
1399 184 : result = heap_copy_tuple_as_datum(tuple, desc);
1400 184 : heap_freetuple(tuple);
1401 :
1402 184 : pfree(values);
1403 184 : pfree(nulls);
1404 :
1405 184 : return result;
1406 : }
1407 :
1408 :
1409 : static Datum
1410 264 : PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
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 264 : idx = 0;
1427 886 : for (i = 0; i < desc->natts; i++)
1428 : {
1429 622 : if (!TupleDescAttr(desc, i)->attisdropped)
1430 520 : idx++;
1431 : }
1432 264 : if (PySequence_Length(sequence) != idx)
1433 6 : 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 258 : values = palloc(sizeof(Datum) * desc->natts);
1439 258 : nulls = palloc(sizeof(bool) * desc->natts);
1440 258 : idx = 0;
1441 860 : for (i = 0; i < desc->natts; ++i)
1442 : {
1443 : PyObject *volatile value;
1444 : PLyObToDatum *att;
1445 :
1446 606 : if (TupleDescAttr(desc, i)->attisdropped)
1447 : {
1448 94 : values[i] = (Datum) 0;
1449 94 : nulls[i] = true;
1450 94 : continue;
1451 : }
1452 :
1453 512 : value = NULL;
1454 512 : att = &arg->u.tuple.atts[i];
1455 512 : PG_TRY();
1456 : {
1457 512 : value = PySequence_GetItem(sequence, idx);
1458 : Assert(value);
1459 :
1460 512 : values[i] = att->func(att, value, &nulls[i], false);
1461 :
1462 508 : Py_XDECREF(value);
1463 508 : value = NULL;
1464 : }
1465 4 : PG_CATCH();
1466 : {
1467 4 : Py_XDECREF(value);
1468 4 : PG_RE_THROW();
1469 : }
1470 508 : PG_END_TRY();
1471 :
1472 508 : idx++;
1473 : }
1474 :
1475 254 : tuple = heap_form_tuple(desc, values, nulls);
1476 254 : result = heap_copy_tuple_as_datum(tuple, desc);
1477 254 : heap_freetuple(tuple);
1478 :
1479 254 : pfree(values);
1480 254 : pfree(nulls);
1481 :
1482 254 : return result;
1483 : }
1484 :
1485 :
1486 : static Datum
1487 50 : PLyGenericObject_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 50 : values = palloc(sizeof(Datum) * desc->natts);
1497 50 : nulls = palloc(sizeof(bool) * desc->natts);
1498 196 : for (i = 0; i < desc->natts; ++i)
1499 : {
1500 : char *key;
1501 : PyObject *volatile value;
1502 : PLyObToDatum *att;
1503 148 : Form_pg_attribute attr = TupleDescAttr(desc, i);
1504 :
1505 148 : if (attr->attisdropped)
1506 : {
1507 48 : values[i] = (Datum) 0;
1508 48 : nulls[i] = true;
1509 48 : continue;
1510 : }
1511 :
1512 100 : key = NameStr(attr->attname);
1513 100 : value = NULL;
1514 100 : att = &arg->u.tuple.atts[i];
1515 100 : PG_TRY();
1516 : {
1517 100 : value = PyObject_GetAttrString(object, key);
1518 100 : 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 2 : 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 98 : values[i] = att->func(att, value, &nulls[i], false);
1540 :
1541 98 : Py_XDECREF(value);
1542 98 : value = NULL;
1543 : }
1544 2 : PG_CATCH();
1545 : {
1546 2 : Py_XDECREF(value);
1547 2 : PG_RE_THROW();
1548 : }
1549 98 : PG_END_TRY();
1550 : }
1551 :
1552 48 : tuple = heap_form_tuple(desc, values, nulls);
1553 48 : result = heap_copy_tuple_as_datum(tuple, desc);
1554 48 : heap_freetuple(tuple);
1555 :
1556 48 : pfree(values);
1557 48 : pfree(nulls);
1558 :
1559 48 : return result;
1560 : }
|