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