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