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/lsyscache.h"
18 #include "utils/memutils.h"
19 #include "utils/numeric.h"
20 #include "utils/syscache.h"
21 #include "utils/typcache.h"
22 
23 #include "plpython.h"
24 
25 #include "plpy_typeio.h"
26 
27 #include "plpy_elog.h"
28 #include "plpy_main.h"
29 
30 
31 /* I/O function caching */
32 static void PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
33 static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes);
34 
35 /* conversion from Datums to Python objects */
36 static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
37 static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
38 static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
39 static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
40 static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
41 static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
42 static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
43 static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
44 static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
45 static PyObject *PLyString_FromDatum(PLyDatumToOb *arg, Datum d);
46 static PyObject *PLyObject_FromTransform(PLyDatumToOb *arg, Datum d);
47 static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
48 
49 /* conversion from Python objects to Datums */
50 static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
51 static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
52 static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
53 static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
54 static Datum PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
55 static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
56 
57 /* conversion from Python objects to composite Datums (used by triggers and SRFs) */
58 static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string);
59 static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping);
60 static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence);
61 static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object);
62 
63 void
PLy_typeinfo_init(PLyTypeInfo * arg,MemoryContext mcxt)64 PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
65 {
66 	arg->is_rowtype = -1;
67 	arg->in.r.natts = arg->out.r.natts = 0;
68 	arg->in.r.atts = NULL;
69 	arg->out.r.atts = NULL;
70 	arg->typ_relid = InvalidOid;
71 	arg->typrel_xmin = InvalidTransactionId;
72 	ItemPointerSetInvalid(&arg->typrel_tid);
73 	arg->mcxt = mcxt;
74 }
75 
76 /*
77  * Conversion functions.  Remember output from Python is input to
78  * PostgreSQL, and vice versa.
79  */
80 void
PLy_input_datum_func(PLyTypeInfo * arg,Oid typeOid,HeapTuple typeTup,Oid langid,List * trftypes)81 PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
82 {
83 	if (arg->is_rowtype > 0)
84 		elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
85 	arg->is_rowtype = 0;
86 	PLy_input_datum_func2(&(arg->in.d), arg->mcxt, typeOid, typeTup, langid, trftypes);
87 }
88 
89 void
PLy_output_datum_func(PLyTypeInfo * arg,HeapTuple typeTup,Oid langid,List * trftypes)90 PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trftypes)
91 {
92 	if (arg->is_rowtype > 0)
93 		elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
94 	arg->is_rowtype = 0;
95 	PLy_output_datum_func2(&(arg->out.d), arg->mcxt, typeTup, langid, trftypes);
96 }
97 
98 void
PLy_input_tuple_funcs(PLyTypeInfo * arg,TupleDesc desc)99 PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
100 {
101 	int			i;
102 	PLyExecutionContext *exec_ctx = PLy_current_execution_context();
103 	MemoryContext oldcxt;
104 
105 	oldcxt = MemoryContextSwitchTo(arg->mcxt);
106 
107 	if (arg->is_rowtype == 0)
108 		elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
109 	arg->is_rowtype = 1;
110 
111 	if (arg->in.r.natts != desc->natts)
112 	{
113 		if (arg->in.r.atts)
114 			pfree(arg->in.r.atts);
115 		arg->in.r.natts = desc->natts;
116 		arg->in.r.atts = palloc0(desc->natts * sizeof(PLyDatumToOb));
117 	}
118 
119 	/* Can this be an unnamed tuple? If not, then an Assert would be enough */
120 	if (desc->tdtypmod != -1)
121 		elog(ERROR, "received unnamed record type as input");
122 
123 	Assert(OidIsValid(desc->tdtypeid));
124 
125 	/*
126 	 * RECORDOID means we got called to create input functions for a tuple
127 	 * fetched by plpy.execute or for an anonymous record type
128 	 */
129 	if (desc->tdtypeid != RECORDOID)
130 	{
131 		HeapTuple	relTup;
132 
133 		/* Get the pg_class tuple corresponding to the type of the input */
134 		arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
135 		relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
136 		if (!HeapTupleIsValid(relTup))
137 			elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
138 
139 		/* Remember XMIN and TID for later validation if cache is still OK */
140 		arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
141 		arg->typrel_tid = relTup->t_self;
142 
143 		ReleaseSysCache(relTup);
144 	}
145 
146 	for (i = 0; i < desc->natts; i++)
147 	{
148 		HeapTuple	typeTup;
149 
150 		if (desc->attrs[i]->attisdropped)
151 			continue;
152 
153 		if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
154 			continue;			/* already set up this entry */
155 
156 		typeTup = SearchSysCache1(TYPEOID,
157 								  ObjectIdGetDatum(desc->attrs[i]->atttypid));
158 		if (!HeapTupleIsValid(typeTup))
159 			elog(ERROR, "cache lookup failed for type %u",
160 				 desc->attrs[i]->atttypid);
161 
162 		PLy_input_datum_func2(&(arg->in.r.atts[i]), arg->mcxt,
163 							  desc->attrs[i]->atttypid,
164 							  typeTup,
165 							  exec_ctx->curr_proc->langid,
166 							  exec_ctx->curr_proc->trftypes);
167 
168 		ReleaseSysCache(typeTup);
169 	}
170 
171 	MemoryContextSwitchTo(oldcxt);
172 }
173 
174 void
PLy_output_tuple_funcs(PLyTypeInfo * arg,TupleDesc desc)175 PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
176 {
177 	int			i;
178 	PLyExecutionContext *exec_ctx = PLy_current_execution_context();
179 	MemoryContext oldcxt;
180 
181 	oldcxt = MemoryContextSwitchTo(arg->mcxt);
182 
183 	if (arg->is_rowtype == 0)
184 		elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
185 	arg->is_rowtype = 1;
186 
187 	if (arg->out.r.natts != desc->natts)
188 	{
189 		if (arg->out.r.atts)
190 			pfree(arg->out.r.atts);
191 		arg->out.r.natts = desc->natts;
192 		arg->out.r.atts = palloc0(desc->natts * sizeof(PLyObToDatum));
193 	}
194 
195 	Assert(OidIsValid(desc->tdtypeid));
196 
197 	/*
198 	 * RECORDOID means we got called to create output functions for an
199 	 * anonymous record type
200 	 */
201 	if (desc->tdtypeid != RECORDOID)
202 	{
203 		HeapTuple	relTup;
204 
205 		/* Get the pg_class tuple corresponding to the type of the output */
206 		arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
207 		relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
208 		if (!HeapTupleIsValid(relTup))
209 			elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
210 
211 		/* Remember XMIN and TID for later validation if cache is still OK */
212 		arg->typrel_xmin = HeapTupleHeaderGetRawXmin(relTup->t_data);
213 		arg->typrel_tid = relTup->t_self;
214 
215 		ReleaseSysCache(relTup);
216 	}
217 
218 	for (i = 0; i < desc->natts; i++)
219 	{
220 		HeapTuple	typeTup;
221 
222 		if (desc->attrs[i]->attisdropped)
223 			continue;
224 
225 		if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
226 			continue;			/* already set up this entry */
227 
228 		typeTup = SearchSysCache1(TYPEOID,
229 								  ObjectIdGetDatum(desc->attrs[i]->atttypid));
230 		if (!HeapTupleIsValid(typeTup))
231 			elog(ERROR, "cache lookup failed for type %u",
232 				 desc->attrs[i]->atttypid);
233 
234 		PLy_output_datum_func2(&(arg->out.r.atts[i]), arg->mcxt, typeTup,
235 							   exec_ctx->curr_proc->langid,
236 							   exec_ctx->curr_proc->trftypes);
237 
238 		ReleaseSysCache(typeTup);
239 	}
240 
241 	MemoryContextSwitchTo(oldcxt);
242 }
243 
244 void
PLy_output_record_funcs(PLyTypeInfo * arg,TupleDesc desc)245 PLy_output_record_funcs(PLyTypeInfo *arg, TupleDesc desc)
246 {
247 	/*
248 	 * If the output record functions are already set, we just have to check
249 	 * if the record descriptor has not changed
250 	 */
251 	if ((arg->is_rowtype == 1) &&
252 		(arg->out.d.typmod != -1) &&
253 		(arg->out.d.typmod == desc->tdtypmod))
254 		return;
255 
256 	/* bless the record to make it known to the typcache lookup code */
257 	BlessTupleDesc(desc);
258 	/* save the freshly generated typmod */
259 	arg->out.d.typmod = desc->tdtypmod;
260 	/* proceed with normal I/O function caching */
261 	PLy_output_tuple_funcs(arg, desc);
262 
263 	/*
264 	 * it should change is_rowtype to 1, so we won't go through this again
265 	 * unless the output record description changes
266 	 */
267 	Assert(arg->is_rowtype == 1);
268 }
269 
270 /*
271  * Transform a tuple into a Python dict object.
272  */
273 PyObject *
PLyDict_FromTuple(PLyTypeInfo * info,HeapTuple tuple,TupleDesc desc)274 PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
275 {
276 	PyObject   *volatile dict;
277 	PLyExecutionContext *exec_ctx = PLy_current_execution_context();
278 	MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx);
279 	MemoryContext oldcontext = CurrentMemoryContext;
280 
281 	if (info->is_rowtype != 1)
282 		elog(ERROR, "PLyTypeInfo structure describes a datum");
283 
284 	dict = PyDict_New();
285 	if (dict == NULL)
286 		PLy_elog(ERROR, "could not create new dictionary");
287 
288 	PG_TRY();
289 	{
290 		int			i;
291 
292 		/*
293 		 * Do the work in the scratch context to avoid leaking memory from the
294 		 * datatype output function calls.
295 		 */
296 		MemoryContextSwitchTo(scratch_context);
297 		for (i = 0; i < info->in.r.natts; i++)
298 		{
299 			char	   *key;
300 			Datum		vattr;
301 			bool		is_null;
302 			PyObject   *value;
303 
304 			if (desc->attrs[i]->attisdropped)
305 				continue;
306 
307 			key = NameStr(desc->attrs[i]->attname);
308 			vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
309 
310 			if (is_null || info->in.r.atts[i].func == NULL)
311 				PyDict_SetItemString(dict, key, Py_None);
312 			else
313 			{
314 				value = (info->in.r.atts[i].func) (&info->in.r.atts[i], vattr);
315 				PyDict_SetItemString(dict, key, value);
316 				Py_DECREF(value);
317 			}
318 		}
319 		MemoryContextSwitchTo(oldcontext);
320 		MemoryContextReset(scratch_context);
321 	}
322 	PG_CATCH();
323 	{
324 		MemoryContextSwitchTo(oldcontext);
325 		Py_DECREF(dict);
326 		PG_RE_THROW();
327 	}
328 	PG_END_TRY();
329 
330 	return dict;
331 }
332 
333 /*
334  *	Convert a Python object to a composite Datum, using all supported
335  *	conversion methods: composite as a string, as a sequence, as a mapping or
336  *	as an object that has __getattr__ support.
337  */
338 Datum
PLyObject_ToCompositeDatum(PLyTypeInfo * info,TupleDesc desc,PyObject * plrv)339 PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
340 {
341 	Datum		datum;
342 
343 	if (PyString_Check(plrv) || PyUnicode_Check(plrv))
344 		datum = PLyString_ToComposite(info, desc, plrv);
345 	else if (PySequence_Check(plrv))
346 		/* composite type as sequence (tuple, list etc) */
347 		datum = PLySequence_ToComposite(info, desc, plrv);
348 	else if (PyMapping_Check(plrv))
349 		/* composite type as mapping (currently only dict) */
350 		datum = PLyMapping_ToComposite(info, desc, plrv);
351 	else
352 		/* returned as smth, must provide method __getattr__(name) */
353 		datum = PLyGenericObject_ToComposite(info, desc, plrv);
354 
355 	return datum;
356 }
357 
358 static void
PLy_output_datum_func2(PLyObToDatum * arg,MemoryContext arg_mcxt,HeapTuple typeTup,Oid langid,List * trftypes)359 PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
360 {
361 	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
362 	Oid			element_type;
363 	Oid			base_type;
364 	Oid			funcid;
365 	MemoryContext oldcxt;
366 
367 	oldcxt = MemoryContextSwitchTo(arg_mcxt);
368 
369 	fmgr_info_cxt(typeStruct->typinput, &arg->typfunc, arg_mcxt);
370 	arg->typoid = HeapTupleGetOid(typeTup);
371 	arg->typmod = -1;
372 	arg->typioparam = getTypeIOParam(typeTup);
373 	arg->typbyval = typeStruct->typbyval;
374 
375 	element_type = get_base_element_type(arg->typoid);
376 	base_type = getBaseType(element_type ? element_type : arg->typoid);
377 
378 	/*
379 	 * Select a conversion function to convert Python objects to PostgreSQL
380 	 * datums.
381 	 */
382 
383 	if ((funcid = get_transform_tosql(base_type, langid, trftypes)))
384 	{
385 		arg->func = PLyObject_ToTransform;
386 		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
387 	}
388 	else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
389 	{
390 		arg->func = PLyObject_ToComposite;
391 	}
392 	else
393 		switch (base_type)
394 		{
395 			case BOOLOID:
396 				arg->func = PLyObject_ToBool;
397 				break;
398 			case BYTEAOID:
399 				arg->func = PLyObject_ToBytea;
400 				break;
401 			default:
402 				arg->func = PLyObject_ToDatum;
403 				break;
404 		}
405 
406 	if (element_type)
407 	{
408 		char		dummy_delim;
409 		Oid			funcid;
410 
411 		if (type_is_rowtype(element_type))
412 			arg->func = PLyObject_ToComposite;
413 
414 		arg->elm = palloc0(sizeof(*arg->elm));
415 		arg->elm->func = arg->func;
416 		arg->elm->typtransform = arg->typtransform;
417 		arg->func = PLySequence_ToArray;
418 
419 		arg->elm->typoid = element_type;
420 		arg->elm->typmod = -1;
421 		get_type_io_data(element_type, IOFunc_input,
422 						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
423 						 &arg->elm->typioparam, &funcid);
424 		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
425 	}
426 
427 	MemoryContextSwitchTo(oldcxt);
428 }
429 
430 static void
PLy_input_datum_func2(PLyDatumToOb * arg,MemoryContext arg_mcxt,Oid typeOid,HeapTuple typeTup,Oid langid,List * trftypes)431 PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
432 {
433 	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
434 	Oid			element_type;
435 	Oid			base_type;
436 	Oid			funcid;
437 	MemoryContext oldcxt;
438 
439 	oldcxt = MemoryContextSwitchTo(arg_mcxt);
440 
441 	/* Get the type's conversion information */
442 	fmgr_info_cxt(typeStruct->typoutput, &arg->typfunc, arg_mcxt);
443 	arg->typoid = HeapTupleGetOid(typeTup);
444 	arg->typmod = -1;
445 	arg->typioparam = getTypeIOParam(typeTup);
446 	arg->typbyval = typeStruct->typbyval;
447 	arg->typlen = typeStruct->typlen;
448 	arg->typalign = typeStruct->typalign;
449 
450 	/* Determine which kind of Python object we will convert to */
451 
452 	element_type = get_base_element_type(typeOid);
453 	base_type = getBaseType(element_type ? element_type : typeOid);
454 
455 	if ((funcid = get_transform_fromsql(base_type, langid, trftypes)))
456 	{
457 		arg->func = PLyObject_FromTransform;
458 		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
459 	}
460 	else
461 		switch (base_type)
462 		{
463 			case BOOLOID:
464 				arg->func = PLyBool_FromBool;
465 				break;
466 			case FLOAT4OID:
467 				arg->func = PLyFloat_FromFloat4;
468 				break;
469 			case FLOAT8OID:
470 				arg->func = PLyFloat_FromFloat8;
471 				break;
472 			case NUMERICOID:
473 				arg->func = PLyDecimal_FromNumeric;
474 				break;
475 			case INT2OID:
476 				arg->func = PLyInt_FromInt16;
477 				break;
478 			case INT4OID:
479 				arg->func = PLyInt_FromInt32;
480 				break;
481 			case INT8OID:
482 				arg->func = PLyLong_FromInt64;
483 				break;
484 			case OIDOID:
485 				arg->func = PLyLong_FromOid;
486 				break;
487 			case BYTEAOID:
488 				arg->func = PLyBytes_FromBytea;
489 				break;
490 			default:
491 				arg->func = PLyString_FromDatum;
492 				break;
493 		}
494 
495 	if (element_type)
496 	{
497 		char		dummy_delim;
498 		Oid			funcid;
499 
500 		arg->elm = palloc0(sizeof(*arg->elm));
501 		arg->elm->func = arg->func;
502 		arg->elm->typtransform = arg->typtransform;
503 		arg->func = PLyList_FromArray;
504 		arg->elm->typoid = element_type;
505 		arg->elm->typmod = -1;
506 		get_type_io_data(element_type, IOFunc_output,
507 						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
508 						 &arg->elm->typioparam, &funcid);
509 		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
510 	}
511 
512 	MemoryContextSwitchTo(oldcxt);
513 }
514 
515 static PyObject *
PLyBool_FromBool(PLyDatumToOb * arg,Datum d)516 PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
517 {
518 	/*
519 	 * We would like to use Py_RETURN_TRUE and Py_RETURN_FALSE here for
520 	 * generating SQL from trigger functions, but those are only supported in
521 	 * Python >= 2.4, and we support older versions.
522 	 * http://docs.python.org/api/boolObjects.html
523 	 */
524 	if (DatumGetBool(d))
525 		return PyBool_FromLong(1);
526 	return PyBool_FromLong(0);
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 = DatumGetByteaP(d);
607 	char	   *str = VARDATA(txt);
608 	size_t		size = VARSIZE(txt) - VARHDRSZ;
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 	PyObject   *list;
635 	int			length;
636 	int			lbound;
637 	int			i;
638 
639 	if (ARR_NDIM(array) == 0)
640 		return PyList_New(0);
641 
642 	if (ARR_NDIM(array) != 1)
643 		ereport(ERROR,
644 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
645 			  errmsg("cannot convert multidimensional array to Python list"),
646 			  errdetail("PL/Python only supports one-dimensional arrays.")));
647 
648 	length = ARR_DIMS(array)[0];
649 	lbound = ARR_LBOUND(array)[0];
650 	list = PyList_New(length);
651 	if (list == NULL)
652 		PLy_elog(ERROR, "could not create new Python list");
653 
654 	for (i = 0; i < length; i++)
655 	{
656 		Datum		elem;
657 		bool		isnull;
658 		int			offset;
659 
660 		offset = lbound + i;
661 		elem = array_ref(array, 1, &offset, arg->typlen,
662 						 elm->typlen, elm->typbyval, elm->typalign,
663 						 &isnull);
664 		if (isnull)
665 		{
666 			Py_INCREF(Py_None);
667 			PyList_SET_ITEM(list, i, Py_None);
668 		}
669 		else
670 			PyList_SET_ITEM(list, i, elm->func(elm, elem));
671 	}
672 
673 	return list;
674 }
675 
676 /*
677  * Convert a Python object to a PostgreSQL bool datum.  This can't go
678  * through the generic conversion function, because Python attaches a
679  * Boolean value to everything, more things than the PostgreSQL bool
680  * type can parse.
681  */
682 static Datum
PLyObject_ToBool(PLyObToDatum * arg,int32 typmod,PyObject * plrv)683 PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
684 {
685 	Datum		rv;
686 
687 	Assert(plrv != Py_None);
688 	rv = BoolGetDatum(PyObject_IsTrue(plrv));
689 
690 	if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
691 		domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
692 
693 	return rv;
694 }
695 
696 /*
697  * Convert a Python object to a PostgreSQL bytea datum.  This doesn't
698  * go through the generic conversion function to circumvent problems
699  * with embedded nulls.  And it's faster this way.
700  */
701 static Datum
PLyObject_ToBytea(PLyObToDatum * arg,int32 typmod,PyObject * plrv)702 PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
703 {
704 	PyObject   *volatile plrv_so = NULL;
705 	Datum		rv;
706 
707 	Assert(plrv != Py_None);
708 
709 	plrv_so = PyObject_Bytes(plrv);
710 	if (!plrv_so)
711 		PLy_elog(ERROR, "could not create bytes representation of Python object");
712 
713 	PG_TRY();
714 	{
715 		char	   *plrv_sc = PyBytes_AsString(plrv_so);
716 		size_t		len = PyBytes_Size(plrv_so);
717 		size_t		size = len + VARHDRSZ;
718 		bytea	   *result = palloc(size);
719 
720 		SET_VARSIZE(result, size);
721 		memcpy(VARDATA(result), plrv_sc, len);
722 		rv = PointerGetDatum(result);
723 	}
724 	PG_CATCH();
725 	{
726 		Py_XDECREF(plrv_so);
727 		PG_RE_THROW();
728 	}
729 	PG_END_TRY();
730 
731 	Py_XDECREF(plrv_so);
732 
733 	if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
734 		domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
735 
736 	return rv;
737 }
738 
739 
740 /*
741  * Convert a Python object to a composite type. First look up the type's
742  * description, then route the Python object through the conversion function
743  * for obtaining PostgreSQL tuples.
744  */
745 static Datum
PLyObject_ToComposite(PLyObToDatum * arg,int32 typmod,PyObject * plrv)746 PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
747 {
748 	Datum		rv;
749 	PLyTypeInfo info;
750 	TupleDesc	desc;
751 	MemoryContext cxt;
752 
753 	if (typmod != -1)
754 		elog(ERROR, "received unnamed record type as input");
755 
756 	/* Create a dummy PLyTypeInfo */
757 	cxt = AllocSetContextCreate(CurrentMemoryContext,
758 								"PL/Python temp context",
759 								ALLOCSET_DEFAULT_SIZES);
760 	MemSet(&info, 0, sizeof(PLyTypeInfo));
761 	PLy_typeinfo_init(&info, cxt);
762 	/* Mark it as needing output routines lookup */
763 	info.is_rowtype = 2;
764 
765 	desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
766 
767 	/*
768 	 * This will set up the dummy PLyTypeInfo's output conversion routines,
769 	 * since we left is_rowtype as 2. A future optimisation could be caching
770 	 * that info instead of looking it up every time a tuple is returned from
771 	 * the function.
772 	 */
773 	rv = PLyObject_ToCompositeDatum(&info, desc, plrv);
774 
775 	ReleaseTupleDesc(desc);
776 
777 	MemoryContextDelete(cxt);
778 
779 	return rv;
780 }
781 
782 
783 /*
784  * Convert Python object to C string in server encoding.
785  */
786 char *
PLyObject_AsString(PyObject * plrv)787 PLyObject_AsString(PyObject *plrv)
788 {
789 	PyObject   *plrv_bo;
790 	char	   *plrv_sc;
791 	size_t		plen;
792 	size_t		slen;
793 
794 	if (PyUnicode_Check(plrv))
795 		plrv_bo = PLyUnicode_Bytes(plrv);
796 	else if (PyFloat_Check(plrv))
797 	{
798 		/* use repr() for floats, str() is lossy */
799 #if PY_MAJOR_VERSION >= 3
800 		PyObject   *s = PyObject_Repr(plrv);
801 
802 		plrv_bo = PLyUnicode_Bytes(s);
803 		Py_XDECREF(s);
804 #else
805 		plrv_bo = PyObject_Repr(plrv);
806 #endif
807 	}
808 	else
809 	{
810 #if PY_MAJOR_VERSION >= 3
811 		PyObject   *s = PyObject_Str(plrv);
812 
813 		plrv_bo = PLyUnicode_Bytes(s);
814 		Py_XDECREF(s);
815 #else
816 		plrv_bo = PyObject_Str(plrv);
817 #endif
818 	}
819 	if (!plrv_bo)
820 		PLy_elog(ERROR, "could not create string representation of Python object");
821 
822 	plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
823 	plen = PyBytes_Size(plrv_bo);
824 	slen = strlen(plrv_sc);
825 
826 	Py_XDECREF(plrv_bo);
827 
828 	if (slen < plen)
829 		ereport(ERROR,
830 				(errcode(ERRCODE_DATATYPE_MISMATCH),
831 				 errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
832 	else if (slen > plen)
833 		elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
834 	pg_verifymbstr(plrv_sc, slen, false);
835 
836 	return plrv_sc;
837 }
838 
839 
840 /*
841  * Generic conversion function: Convert PyObject to cstring and
842  * cstring into PostgreSQL type.
843  */
844 static Datum
PLyObject_ToDatum(PLyObToDatum * arg,int32 typmod,PyObject * plrv)845 PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
846 {
847 	Assert(plrv != Py_None);
848 
849 	return InputFunctionCall(&arg->typfunc,
850 							 PLyObject_AsString(plrv),
851 							 arg->typioparam,
852 							 typmod);
853 }
854 
855 
856 static Datum
PLyObject_ToTransform(PLyObToDatum * arg,int32 typmod,PyObject * plrv)857 PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
858 {
859 	return FunctionCall1(&arg->typtransform, PointerGetDatum(plrv));
860 }
861 
862 
863 static Datum
PLySequence_ToArray(PLyObToDatum * arg,int32 typmod,PyObject * plrv)864 PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
865 {
866 	ArrayType  *array;
867 	Datum		rv;
868 	int			i;
869 	Datum	   *elems;
870 	bool	   *nulls;
871 	int			len;
872 	int			lbs;
873 
874 	Assert(plrv != Py_None);
875 
876 	if (!PySequence_Check(plrv))
877 		PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");
878 
879 	len = PySequence_Length(plrv);
880 	elems = palloc(sizeof(*elems) * len);
881 	nulls = palloc(sizeof(*nulls) * len);
882 
883 	for (i = 0; i < len; i++)
884 	{
885 		PyObject   *obj = PySequence_GetItem(plrv, i);
886 
887 		if (obj == Py_None)
888 			nulls[i] = true;
889 		else
890 		{
891 			nulls[i] = false;
892 			elems[i] = arg->elm->func(arg->elm, -1, obj);
893 		}
894 		Py_XDECREF(obj);
895 	}
896 
897 	lbs = 1;
898 	array = construct_md_array(elems, nulls, 1, &len, &lbs,
899 							   get_base_element_type(arg->typoid), arg->elm->typlen, arg->elm->typbyval, arg->elm->typalign);
900 
901 	/*
902 	 * If the result type is a domain of array, the resulting array must be
903 	 * checked.
904 	 */
905 	rv = PointerGetDatum(array);
906 	if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
907 		domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
908 	return rv;
909 }
910 
911 
912 static Datum
PLyString_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * string)913 PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
914 {
915 	Datum		result;
916 	HeapTuple	typeTup;
917 	PLyTypeInfo locinfo;
918 	PLyExecutionContext *exec_ctx = PLy_current_execution_context();
919 	MemoryContext cxt;
920 
921 	/* Create a dummy PLyTypeInfo */
922 	cxt = AllocSetContextCreate(CurrentMemoryContext,
923 								"PL/Python temp context",
924 								ALLOCSET_DEFAULT_SIZES);
925 	MemSet(&locinfo, 0, sizeof(PLyTypeInfo));
926 	PLy_typeinfo_init(&locinfo, cxt);
927 
928 	typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid));
929 	if (!HeapTupleIsValid(typeTup))
930 		elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
931 
932 	PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup,
933 						   exec_ctx->curr_proc->langid,
934 						   exec_ctx->curr_proc->trftypes);
935 
936 	ReleaseSysCache(typeTup);
937 
938 	result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string);
939 
940 	MemoryContextDelete(cxt);
941 
942 	return result;
943 }
944 
945 
946 static Datum
PLyMapping_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * mapping)947 PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
948 {
949 	Datum		result;
950 	HeapTuple	tuple;
951 	Datum	   *values;
952 	bool	   *nulls;
953 	volatile int i;
954 
955 	Assert(PyMapping_Check(mapping));
956 
957 	if (info->is_rowtype == 2)
958 		PLy_output_tuple_funcs(info, desc);
959 	Assert(info->is_rowtype == 1);
960 
961 	/* Build tuple */
962 	values = palloc(sizeof(Datum) * desc->natts);
963 	nulls = palloc(sizeof(bool) * desc->natts);
964 	for (i = 0; i < desc->natts; ++i)
965 	{
966 		char	   *key;
967 		PyObject   *volatile value;
968 		PLyObToDatum *att;
969 
970 		if (desc->attrs[i]->attisdropped)
971 		{
972 			values[i] = (Datum) 0;
973 			nulls[i] = true;
974 			continue;
975 		}
976 
977 		key = NameStr(desc->attrs[i]->attname);
978 		value = NULL;
979 		att = &info->out.r.atts[i];
980 		PG_TRY();
981 		{
982 			value = PyMapping_GetItemString(mapping, key);
983 			if (value == Py_None)
984 			{
985 				values[i] = (Datum) NULL;
986 				nulls[i] = true;
987 			}
988 			else if (value)
989 			{
990 				values[i] = (att->func) (att, -1, value);
991 				nulls[i] = false;
992 			}
993 			else
994 				ereport(ERROR,
995 						(errcode(ERRCODE_UNDEFINED_COLUMN),
996 						 errmsg("key \"%s\" not found in mapping", key),
997 						 errhint("To return null in a column, "
998 								 "add the value None to the mapping with the key named after the column.")));
999 
1000 			Py_XDECREF(value);
1001 			value = NULL;
1002 		}
1003 		PG_CATCH();
1004 		{
1005 			Py_XDECREF(value);
1006 			PG_RE_THROW();
1007 		}
1008 		PG_END_TRY();
1009 	}
1010 
1011 	tuple = heap_form_tuple(desc, values, nulls);
1012 	result = heap_copy_tuple_as_datum(tuple, desc);
1013 	heap_freetuple(tuple);
1014 
1015 	pfree(values);
1016 	pfree(nulls);
1017 
1018 	return result;
1019 }
1020 
1021 
1022 static Datum
PLySequence_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * sequence)1023 PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
1024 {
1025 	Datum		result;
1026 	HeapTuple	tuple;
1027 	Datum	   *values;
1028 	bool	   *nulls;
1029 	volatile int idx;
1030 	volatile int i;
1031 
1032 	Assert(PySequence_Check(sequence));
1033 
1034 	/*
1035 	 * Check that sequence length is exactly same as PG tuple's. We actually
1036 	 * can ignore exceeding items or assume missing ones as null but to avoid
1037 	 * plpython developer's errors we are strict here
1038 	 */
1039 	idx = 0;
1040 	for (i = 0; i < desc->natts; i++)
1041 	{
1042 		if (!desc->attrs[i]->attisdropped)
1043 			idx++;
1044 	}
1045 	if (PySequence_Length(sequence) != idx)
1046 		ereport(ERROR,
1047 				(errcode(ERRCODE_DATATYPE_MISMATCH),
1048 				 errmsg("length of returned sequence did not match number of columns in row")));
1049 
1050 	if (info->is_rowtype == 2)
1051 		PLy_output_tuple_funcs(info, desc);
1052 	Assert(info->is_rowtype == 1);
1053 
1054 	/* Build tuple */
1055 	values = palloc(sizeof(Datum) * desc->natts);
1056 	nulls = palloc(sizeof(bool) * desc->natts);
1057 	idx = 0;
1058 	for (i = 0; i < desc->natts; ++i)
1059 	{
1060 		PyObject   *volatile value;
1061 		PLyObToDatum *att;
1062 
1063 		if (desc->attrs[i]->attisdropped)
1064 		{
1065 			values[i] = (Datum) 0;
1066 			nulls[i] = true;
1067 			continue;
1068 		}
1069 
1070 		value = NULL;
1071 		att = &info->out.r.atts[i];
1072 		PG_TRY();
1073 		{
1074 			value = PySequence_GetItem(sequence, idx);
1075 			Assert(value);
1076 			if (value == Py_None)
1077 			{
1078 				values[i] = (Datum) NULL;
1079 				nulls[i] = true;
1080 			}
1081 			else if (value)
1082 			{
1083 				values[i] = (att->func) (att, -1, value);
1084 				nulls[i] = false;
1085 			}
1086 
1087 			Py_XDECREF(value);
1088 			value = NULL;
1089 		}
1090 		PG_CATCH();
1091 		{
1092 			Py_XDECREF(value);
1093 			PG_RE_THROW();
1094 		}
1095 		PG_END_TRY();
1096 
1097 		idx++;
1098 	}
1099 
1100 	tuple = heap_form_tuple(desc, values, nulls);
1101 	result = heap_copy_tuple_as_datum(tuple, desc);
1102 	heap_freetuple(tuple);
1103 
1104 	pfree(values);
1105 	pfree(nulls);
1106 
1107 	return result;
1108 }
1109 
1110 
1111 static Datum
PLyGenericObject_ToComposite(PLyTypeInfo * info,TupleDesc desc,PyObject * object)1112 PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object)
1113 {
1114 	Datum		result;
1115 	HeapTuple	tuple;
1116 	Datum	   *values;
1117 	bool	   *nulls;
1118 	volatile int i;
1119 
1120 	if (info->is_rowtype == 2)
1121 		PLy_output_tuple_funcs(info, desc);
1122 	Assert(info->is_rowtype == 1);
1123 
1124 	/* Build tuple */
1125 	values = palloc(sizeof(Datum) * desc->natts);
1126 	nulls = palloc(sizeof(bool) * desc->natts);
1127 	for (i = 0; i < desc->natts; ++i)
1128 	{
1129 		char	   *key;
1130 		PyObject   *volatile value;
1131 		PLyObToDatum *att;
1132 
1133 		if (desc->attrs[i]->attisdropped)
1134 		{
1135 			values[i] = (Datum) 0;
1136 			nulls[i] = true;
1137 			continue;
1138 		}
1139 
1140 		key = NameStr(desc->attrs[i]->attname);
1141 		value = NULL;
1142 		att = &info->out.r.atts[i];
1143 		PG_TRY();
1144 		{
1145 			value = PyObject_GetAttrString(object, key);
1146 			if (value == Py_None)
1147 			{
1148 				values[i] = (Datum) NULL;
1149 				nulls[i] = true;
1150 			}
1151 			else if (value)
1152 			{
1153 				values[i] = (att->func) (att, -1, value);
1154 				nulls[i] = false;
1155 			}
1156 			else
1157 				ereport(ERROR,
1158 						(errcode(ERRCODE_UNDEFINED_COLUMN),
1159 						 errmsg("attribute \"%s\" does not exist in Python object", key),
1160 						 errhint("To return null in a column, "
1161 						   "let the returned object have an attribute named "
1162 								 "after column with value None.")));
1163 
1164 			Py_XDECREF(value);
1165 			value = NULL;
1166 		}
1167 		PG_CATCH();
1168 		{
1169 			Py_XDECREF(value);
1170 			PG_RE_THROW();
1171 		}
1172 		PG_END_TRY();
1173 	}
1174 
1175 	tuple = heap_form_tuple(desc, values, nulls);
1176 	result = heap_copy_tuple_as_datum(tuple, desc);
1177 	heap_freetuple(tuple);
1178 
1179 	pfree(values);
1180 	pfree(nulls);
1181 
1182 	return result;
1183 }
1184