Header And Logo

PostgreSQL
| The world's most advanced open source database.

plpy_typeio.c

Go to the documentation of this file.
00001 /*
00002  * transforming Datums to Python objects and vice versa
00003  *
00004  * src/pl/plpython/plpy_typeio.c
00005  */
00006 
00007 #include "postgres.h"
00008 
00009 #include "access/htup_details.h"
00010 #include "access/transam.h"
00011 #include "catalog/pg_type.h"
00012 #include "funcapi.h"
00013 #include "mb/pg_wchar.h"
00014 #include "parser/parse_type.h"
00015 #include "utils/array.h"
00016 #include "utils/builtins.h"
00017 #include "utils/lsyscache.h"
00018 #include "utils/memutils.h"
00019 #include "utils/syscache.h"
00020 #include "utils/typcache.h"
00021 
00022 #include "plpython.h"
00023 
00024 #include "plpy_typeio.h"
00025 
00026 #include "plpy_elog.h"
00027 #include "plpy_main.h"
00028 
00029 
00030 /* I/O function caching */
00031 static void PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup);
00032 static void PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup);
00033 
00034 /* conversion from Datums to Python objects */
00035 static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
00036 static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
00037 static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
00038 static PyObject *PLyFloat_FromNumeric(PLyDatumToOb *arg, Datum d);
00039 static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
00040 static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
00041 static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
00042 static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
00043 static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
00044 static PyObject *PLyString_FromDatum(PLyDatumToOb *arg, Datum d);
00045 static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
00046 
00047 /* conversion from Python objects to Datums */
00048 static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
00049 static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
00050 static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
00051 static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
00052 static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv);
00053 
00054 /* conversion from Python objects to composite Datums (used by triggers and SRFs) */
00055 static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string);
00056 static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping);
00057 static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence);
00058 static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object);
00059 
00060 /* make allocations in the TopMemoryContext */
00061 static void perm_fmgr_info(Oid functionId, FmgrInfo *finfo);
00062 
00063 void
00064 PLy_typeinfo_init(PLyTypeInfo *arg)
00065 {
00066     arg->is_rowtype = -1;
00067     arg->in.r.natts = arg->out.r.natts = 0;
00068     arg->in.r.atts = NULL;
00069     arg->out.r.atts = NULL;
00070     arg->typ_relid = InvalidOid;
00071     arg->typrel_xmin = InvalidTransactionId;
00072     ItemPointerSetInvalid(&arg->typrel_tid);
00073 }
00074 
00075 void
00076 PLy_typeinfo_dealloc(PLyTypeInfo *arg)
00077 {
00078     if (arg->is_rowtype == 1)
00079     {
00080         int         i;
00081 
00082         for (i = 0; i < arg->in.r.natts; i++)
00083         {
00084             if (arg->in.r.atts[i].elm != NULL)
00085                 PLy_free(arg->in.r.atts[i].elm);
00086         }
00087         if (arg->in.r.atts)
00088             PLy_free(arg->in.r.atts);
00089         for (i = 0; i < arg->out.r.natts; i++)
00090         {
00091             if (arg->out.r.atts[i].elm != NULL)
00092                 PLy_free(arg->out.r.atts[i].elm);
00093         }
00094         if (arg->out.r.atts)
00095             PLy_free(arg->out.r.atts);
00096     }
00097 }
00098 
00099 /*
00100  * Conversion functions.  Remember output from Python is input to
00101  * PostgreSQL, and vice versa.
00102  */
00103 void
00104 PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup)
00105 {
00106     if (arg->is_rowtype > 0)
00107         elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
00108     arg->is_rowtype = 0;
00109     PLy_input_datum_func2(&(arg->in.d), typeOid, typeTup);
00110 }
00111 
00112 void
00113 PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup)
00114 {
00115     if (arg->is_rowtype > 0)
00116         elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
00117     arg->is_rowtype = 0;
00118     PLy_output_datum_func2(&(arg->out.d), typeTup);
00119 }
00120 
00121 void
00122 PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
00123 {
00124     int         i;
00125 
00126     if (arg->is_rowtype == 0)
00127         elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
00128     arg->is_rowtype = 1;
00129 
00130     if (arg->in.r.natts != desc->natts)
00131     {
00132         if (arg->in.r.atts)
00133             PLy_free(arg->in.r.atts);
00134         arg->in.r.natts = desc->natts;
00135         arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
00136     }
00137 
00138     /* Can this be an unnamed tuple? If not, then an Assert would be enough */
00139     if (desc->tdtypmod != -1)
00140         elog(ERROR, "received unnamed record type as input");
00141 
00142     Assert(OidIsValid(desc->tdtypeid));
00143 
00144     /*
00145      * RECORDOID means we got called to create input functions for a tuple
00146      * fetched by plpy.execute or for an anonymous record type
00147      */
00148     if (desc->tdtypeid != RECORDOID)
00149     {
00150         HeapTuple   relTup;
00151 
00152         /* Get the pg_class tuple corresponding to the type of the input */
00153         arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
00154         relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
00155         if (!HeapTupleIsValid(relTup))
00156             elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
00157 
00158         /* Remember XMIN and TID for later validation if cache is still OK */
00159         arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
00160         arg->typrel_tid = relTup->t_self;
00161 
00162         ReleaseSysCache(relTup);
00163     }
00164 
00165     for (i = 0; i < desc->natts; i++)
00166     {
00167         HeapTuple   typeTup;
00168 
00169         if (desc->attrs[i]->attisdropped)
00170             continue;
00171 
00172         if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
00173             continue;           /* already set up this entry */
00174 
00175         typeTup = SearchSysCache1(TYPEOID,
00176                                   ObjectIdGetDatum(desc->attrs[i]->atttypid));
00177         if (!HeapTupleIsValid(typeTup))
00178             elog(ERROR, "cache lookup failed for type %u",
00179                  desc->attrs[i]->atttypid);
00180 
00181         PLy_input_datum_func2(&(arg->in.r.atts[i]),
00182                               desc->attrs[i]->atttypid,
00183                               typeTup);
00184 
00185         ReleaseSysCache(typeTup);
00186     }
00187 }
00188 
00189 void
00190 PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
00191 {
00192     int         i;
00193 
00194     if (arg->is_rowtype == 0)
00195         elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
00196     arg->is_rowtype = 1;
00197 
00198     if (arg->out.r.natts != desc->natts)
00199     {
00200         if (arg->out.r.atts)
00201             PLy_free(arg->out.r.atts);
00202         arg->out.r.natts = desc->natts;
00203         arg->out.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
00204     }
00205 
00206     Assert(OidIsValid(desc->tdtypeid));
00207 
00208     /*
00209      * RECORDOID means we got called to create output functions for an
00210      * anonymous record type
00211      */
00212     if (desc->tdtypeid != RECORDOID)
00213     {
00214         HeapTuple   relTup;
00215 
00216         /* Get the pg_class tuple corresponding to the type of the output */
00217         arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
00218         relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
00219         if (!HeapTupleIsValid(relTup))
00220             elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
00221 
00222         /* Remember XMIN and TID for later validation if cache is still OK */
00223         arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
00224         arg->typrel_tid = relTup->t_self;
00225 
00226         ReleaseSysCache(relTup);
00227     }
00228 
00229     for (i = 0; i < desc->natts; i++)
00230     {
00231         HeapTuple   typeTup;
00232 
00233         if (desc->attrs[i]->attisdropped)
00234             continue;
00235 
00236         if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
00237             continue;           /* already set up this entry */
00238 
00239         typeTup = SearchSysCache1(TYPEOID,
00240                                   ObjectIdGetDatum(desc->attrs[i]->atttypid));
00241         if (!HeapTupleIsValid(typeTup))
00242             elog(ERROR, "cache lookup failed for type %u",
00243                  desc->attrs[i]->atttypid);
00244 
00245         PLy_output_datum_func2(&(arg->out.r.atts[i]), typeTup);
00246 
00247         ReleaseSysCache(typeTup);
00248     }
00249 }
00250 
00251 void
00252 PLy_output_record_funcs(PLyTypeInfo *arg, TupleDesc desc)
00253 {
00254     /*
00255      * If the output record functions are already set, we just have to check
00256      * if the record descriptor has not changed
00257      */
00258     if ((arg->is_rowtype == 1) &&
00259         (arg->out.d.typmod != -1) &&
00260         (arg->out.d.typmod == desc->tdtypmod))
00261         return;
00262 
00263     /* bless the record to make it known to the typcache lookup code */
00264     BlessTupleDesc(desc);
00265     /* save the freshly generated typmod */
00266     arg->out.d.typmod = desc->tdtypmod;
00267     /* proceed with normal I/O function caching */
00268     PLy_output_tuple_funcs(arg, desc);
00269 
00270     /*
00271      * it should change is_rowtype to 1, so we won't go through this again
00272      * unless the output record description changes
00273      */
00274     Assert(arg->is_rowtype == 1);
00275 }
00276 
00277 /*
00278  * Transform a tuple into a Python dict object.
00279  */
00280 PyObject *
00281 PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
00282 {
00283     PyObject   *volatile dict;
00284     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
00285     MemoryContext oldcontext = CurrentMemoryContext;
00286     int         i;
00287 
00288     if (info->is_rowtype != 1)
00289         elog(ERROR, "PLyTypeInfo structure describes a datum");
00290 
00291     dict = PyDict_New();
00292     if (dict == NULL)
00293         PLy_elog(ERROR, "could not create new dictionary");
00294 
00295     PG_TRY();
00296     {
00297         /*
00298          * Do the work in the scratch context to avoid leaking memory from the
00299          * datatype output function calls.
00300          */
00301         MemoryContextSwitchTo(exec_ctx->scratch_ctx);
00302         for (i = 0; i < info->in.r.natts; i++)
00303         {
00304             char       *key;
00305             Datum       vattr;
00306             bool        is_null;
00307             PyObject   *value;
00308 
00309             if (desc->attrs[i]->attisdropped)
00310                 continue;
00311 
00312             key = NameStr(desc->attrs[i]->attname);
00313             vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
00314 
00315             if (is_null || info->in.r.atts[i].func == NULL)
00316                 PyDict_SetItemString(dict, key, Py_None);
00317             else
00318             {
00319                 value = (info->in.r.atts[i].func) (&info->in.r.atts[i], vattr);
00320                 PyDict_SetItemString(dict, key, value);
00321                 Py_DECREF(value);
00322             }
00323         }
00324         MemoryContextSwitchTo(oldcontext);
00325         MemoryContextReset(exec_ctx->scratch_ctx);
00326     }
00327     PG_CATCH();
00328     {
00329         MemoryContextSwitchTo(oldcontext);
00330         Py_DECREF(dict);
00331         PG_RE_THROW();
00332     }
00333     PG_END_TRY();
00334 
00335     return dict;
00336 }
00337 
00338 /*
00339  *  Convert a Python object to a composite Datum, using all supported
00340  *  conversion methods: composite as a string, as a sequence, as a mapping or
00341  *  as an object that has __getattr__ support.
00342  */
00343 Datum
00344 PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
00345 {
00346     Datum       datum;
00347 
00348     if (PyString_Check(plrv) || PyUnicode_Check(plrv))
00349         datum = PLyString_ToComposite(info, desc, plrv);
00350     else if (PySequence_Check(plrv))
00351         /* composite type as sequence (tuple, list etc) */
00352         datum = PLySequence_ToComposite(info, desc, plrv);
00353     else if (PyMapping_Check(plrv))
00354         /* composite type as mapping (currently only dict) */
00355         datum = PLyMapping_ToComposite(info, desc, plrv);
00356     else
00357         /* returned as smth, must provide method __getattr__(name) */
00358         datum = PLyGenericObject_ToComposite(info, desc, plrv);
00359 
00360     return datum;
00361 }
00362 
00363 static void
00364 PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup)
00365 {
00366     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
00367     Oid         element_type;
00368 
00369     perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
00370     arg->typoid = HeapTupleGetOid(typeTup);
00371     arg->typmod = -1;
00372     arg->typioparam = getTypeIOParam(typeTup);
00373     arg->typbyval = typeStruct->typbyval;
00374 
00375     element_type = get_element_type(arg->typoid);
00376 
00377     /*
00378      * Select a conversion function to convert Python objects to PostgreSQL
00379      * datums.  Most data types can go through the generic function.
00380      */
00381     switch (getBaseType(element_type ? element_type : arg->typoid))
00382     {
00383         case BOOLOID:
00384             arg->func = PLyObject_ToBool;
00385             break;
00386         case BYTEAOID:
00387             arg->func = PLyObject_ToBytea;
00388             break;
00389         default:
00390             arg->func = PLyObject_ToDatum;
00391             break;
00392     }
00393 
00394     /* Composite types need their own input routine, though */
00395     if (typeStruct->typtype == TYPTYPE_COMPOSITE)
00396     {
00397         arg->func = PLyObject_ToComposite;
00398     }
00399 
00400     if (element_type)
00401     {
00402         char        dummy_delim;
00403         Oid         funcid;
00404 
00405         if (type_is_rowtype(element_type))
00406             ereport(ERROR,
00407                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00408                      errmsg("PL/Python functions cannot return type %s",
00409                             format_type_be(arg->typoid)),
00410                      errdetail("PL/Python does not support conversion to arrays of row types.")));
00411 
00412         arg->elm = PLy_malloc0(sizeof(*arg->elm));
00413         arg->elm->func = arg->func;
00414         arg->func = PLySequence_ToArray;
00415 
00416         arg->elm->typoid = element_type;
00417         arg->elm->typmod = -1;
00418         get_type_io_data(element_type, IOFunc_input,
00419                          &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
00420                          &arg->elm->typioparam, &funcid);
00421         perm_fmgr_info(funcid, &arg->elm->typfunc);
00422     }
00423 }
00424 
00425 static void
00426 PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup)
00427 {
00428     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
00429     Oid         element_type = get_element_type(typeOid);
00430 
00431     /* Get the type's conversion information */
00432     perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
00433     arg->typoid = HeapTupleGetOid(typeTup);
00434     arg->typmod = -1;
00435     arg->typioparam = getTypeIOParam(typeTup);
00436     arg->typbyval = typeStruct->typbyval;
00437     arg->typlen = typeStruct->typlen;
00438     arg->typalign = typeStruct->typalign;
00439 
00440     /* Determine which kind of Python object we will convert to */
00441     switch (getBaseType(element_type ? element_type : typeOid))
00442     {
00443         case BOOLOID:
00444             arg->func = PLyBool_FromBool;
00445             break;
00446         case FLOAT4OID:
00447             arg->func = PLyFloat_FromFloat4;
00448             break;
00449         case FLOAT8OID:
00450             arg->func = PLyFloat_FromFloat8;
00451             break;
00452         case NUMERICOID:
00453             arg->func = PLyFloat_FromNumeric;
00454             break;
00455         case INT2OID:
00456             arg->func = PLyInt_FromInt16;
00457             break;
00458         case INT4OID:
00459             arg->func = PLyInt_FromInt32;
00460             break;
00461         case INT8OID:
00462             arg->func = PLyLong_FromInt64;
00463             break;
00464         case OIDOID:
00465             arg->func = PLyLong_FromOid;
00466             break;
00467         case BYTEAOID:
00468             arg->func = PLyBytes_FromBytea;
00469             break;
00470         default:
00471             arg->func = PLyString_FromDatum;
00472             break;
00473     }
00474 
00475     if (element_type)
00476     {
00477         char        dummy_delim;
00478         Oid         funcid;
00479 
00480         arg->elm = PLy_malloc0(sizeof(*arg->elm));
00481         arg->elm->func = arg->func;
00482         arg->func = PLyList_FromArray;
00483         arg->elm->typoid = element_type;
00484         arg->elm->typmod = -1;
00485         get_type_io_data(element_type, IOFunc_output,
00486                          &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
00487                          &arg->elm->typioparam, &funcid);
00488         perm_fmgr_info(funcid, &arg->elm->typfunc);
00489     }
00490 }
00491 
00492 static PyObject *
00493 PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
00494 {
00495     /*
00496      * We would like to use Py_RETURN_TRUE and Py_RETURN_FALSE here for
00497      * generating SQL from trigger functions, but those are only supported in
00498      * Python >= 2.4, and we support older versions.
00499      * http://docs.python.org/api/boolObjects.html
00500      */
00501     if (DatumGetBool(d))
00502         return PyBool_FromLong(1);
00503     return PyBool_FromLong(0);
00504 }
00505 
00506 static PyObject *
00507 PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
00508 {
00509     return PyFloat_FromDouble(DatumGetFloat4(d));
00510 }
00511 
00512 static PyObject *
00513 PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
00514 {
00515     return PyFloat_FromDouble(DatumGetFloat8(d));
00516 }
00517 
00518 static PyObject *
00519 PLyFloat_FromNumeric(PLyDatumToOb *arg, Datum d)
00520 {
00521     /*
00522      * Numeric is cast to a PyFloat: This results in a loss of precision Would
00523      * it be better to cast to PyString?
00524      */
00525     Datum       f = DirectFunctionCall1(numeric_float8, d);
00526     double      x = DatumGetFloat8(f);
00527 
00528     return PyFloat_FromDouble(x);
00529 }
00530 
00531 static PyObject *
00532 PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
00533 {
00534     return PyInt_FromLong(DatumGetInt16(d));
00535 }
00536 
00537 static PyObject *
00538 PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
00539 {
00540     return PyInt_FromLong(DatumGetInt32(d));
00541 }
00542 
00543 static PyObject *
00544 PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
00545 {
00546     /* on 32 bit platforms "long" may be too small */
00547     if (sizeof(int64) > sizeof(long))
00548         return PyLong_FromLongLong(DatumGetInt64(d));
00549     else
00550         return PyLong_FromLong(DatumGetInt64(d));
00551 }
00552 
00553 static PyObject *
00554 PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
00555 {
00556     return PyLong_FromUnsignedLong(DatumGetObjectId(d));
00557 }
00558 
00559 static PyObject *
00560 PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
00561 {
00562     text       *txt = DatumGetByteaP(d);
00563     char       *str = VARDATA(txt);
00564     size_t      size = VARSIZE(txt) - VARHDRSZ;
00565 
00566     return PyBytes_FromStringAndSize(str, size);
00567 }
00568 
00569 static PyObject *
00570 PLyString_FromDatum(PLyDatumToOb *arg, Datum d)
00571 {
00572     char       *x = OutputFunctionCall(&arg->typfunc, d);
00573     PyObject   *r = PyString_FromString(x);
00574 
00575     pfree(x);
00576     return r;
00577 }
00578 
00579 static PyObject *
00580 PLyList_FromArray(PLyDatumToOb *arg, Datum d)
00581 {
00582     ArrayType  *array = DatumGetArrayTypeP(d);
00583     PLyDatumToOb *elm = arg->elm;
00584     PyObject   *list;
00585     int         length;
00586     int         lbound;
00587     int         i;
00588 
00589     if (ARR_NDIM(array) == 0)
00590         return PyList_New(0);
00591 
00592     if (ARR_NDIM(array) != 1)
00593         ereport(ERROR,
00594                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00595               errmsg("cannot convert multidimensional array to Python list"),
00596               errdetail("PL/Python only supports one-dimensional arrays.")));
00597 
00598     length = ARR_DIMS(array)[0];
00599     lbound = ARR_LBOUND(array)[0];
00600     list = PyList_New(length);
00601     if (list == NULL)
00602         PLy_elog(ERROR, "could not create new Python list");
00603 
00604     for (i = 0; i < length; i++)
00605     {
00606         Datum       elem;
00607         bool        isnull;
00608         int         offset;
00609 
00610         offset = lbound + i;
00611         elem = array_ref(array, 1, &offset, arg->typlen,
00612                          elm->typlen, elm->typbyval, elm->typalign,
00613                          &isnull);
00614         if (isnull)
00615         {
00616             Py_INCREF(Py_None);
00617             PyList_SET_ITEM(list, i, Py_None);
00618         }
00619         else
00620             PyList_SET_ITEM(list, i, elm->func(elm, elem));
00621     }
00622 
00623     return list;
00624 }
00625 
00626 /*
00627  * Convert a Python object to a PostgreSQL bool datum.  This can't go
00628  * through the generic conversion function, because Python attaches a
00629  * Boolean value to everything, more things than the PostgreSQL bool
00630  * type can parse.
00631  */
00632 static Datum
00633 PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
00634 {
00635     Datum       rv;
00636 
00637     Assert(plrv != Py_None);
00638     rv = BoolGetDatum(PyObject_IsTrue(plrv));
00639 
00640     if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
00641         domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
00642 
00643     return rv;
00644 }
00645 
00646 /*
00647  * Convert a Python object to a PostgreSQL bytea datum.  This doesn't
00648  * go through the generic conversion function to circumvent problems
00649  * with embedded nulls.  And it's faster this way.
00650  */
00651 static Datum
00652 PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
00653 {
00654     PyObject   *volatile plrv_so = NULL;
00655     Datum       rv;
00656 
00657     Assert(plrv != Py_None);
00658 
00659     plrv_so = PyObject_Bytes(plrv);
00660     if (!plrv_so)
00661         PLy_elog(ERROR, "could not create bytes representation of Python object");
00662 
00663     PG_TRY();
00664     {
00665         char       *plrv_sc = PyBytes_AsString(plrv_so);
00666         size_t      len = PyBytes_Size(plrv_so);
00667         size_t      size = len + VARHDRSZ;
00668         bytea      *result = palloc(size);
00669 
00670         SET_VARSIZE(result, size);
00671         memcpy(VARDATA(result), plrv_sc, len);
00672         rv = PointerGetDatum(result);
00673     }
00674     PG_CATCH();
00675     {
00676         Py_XDECREF(plrv_so);
00677         PG_RE_THROW();
00678     }
00679     PG_END_TRY();
00680 
00681     Py_XDECREF(plrv_so);
00682 
00683     if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
00684         domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);
00685 
00686     return rv;
00687 }
00688 
00689 
00690 /*
00691  * Convert a Python object to a composite type. First look up the type's
00692  * description, then route the Python object through the conversion function
00693  * for obtaining PostgreSQL tuples.
00694  */
00695 static Datum
00696 PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
00697 {
00698     Datum       rv;
00699     PLyTypeInfo info;
00700     TupleDesc   desc;
00701 
00702     if (typmod != -1)
00703         elog(ERROR, "received unnamed record type as input");
00704 
00705     /* Create a dummy PLyTypeInfo */
00706     MemSet(&info, 0, sizeof(PLyTypeInfo));
00707     PLy_typeinfo_init(&info);
00708     /* Mark it as needing output routines lookup */
00709     info.is_rowtype = 2;
00710 
00711     desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
00712 
00713     /*
00714      * This will set up the dummy PLyTypeInfo's output conversion routines,
00715      * since we left is_rowtype as 2. A future optimisation could be caching
00716      * that info instead of looking it up every time a tuple is returned from
00717      * the function.
00718      */
00719     rv = PLyObject_ToCompositeDatum(&info, desc, plrv);
00720 
00721     PLy_typeinfo_dealloc(&info);
00722 
00723     return rv;
00724 }
00725 
00726 
00727 /*
00728  * Generic conversion function: Convert PyObject to cstring and
00729  * cstring into PostgreSQL type.
00730  */
00731 static Datum
00732 PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
00733 {
00734     PyObject   *volatile plrv_bo = NULL;
00735     Datum       rv;
00736 
00737     Assert(plrv != Py_None);
00738 
00739     if (PyUnicode_Check(plrv))
00740         plrv_bo = PLyUnicode_Bytes(plrv);
00741     else
00742     {
00743 #if PY_MAJOR_VERSION >= 3
00744         PyObject   *s = PyObject_Str(plrv);
00745 
00746         plrv_bo = PLyUnicode_Bytes(s);
00747         Py_XDECREF(s);
00748 #else
00749         plrv_bo = PyObject_Str(plrv);
00750 #endif
00751     }
00752     if (!plrv_bo)
00753         PLy_elog(ERROR, "could not create string representation of Python object");
00754 
00755     PG_TRY();
00756     {
00757         char       *plrv_sc = PyBytes_AsString(plrv_bo);
00758         size_t      plen = PyBytes_Size(plrv_bo);
00759         size_t      slen = strlen(plrv_sc);
00760 
00761         if (slen < plen)
00762             ereport(ERROR,
00763                     (errcode(ERRCODE_DATATYPE_MISMATCH),
00764                      errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
00765         else if (slen > plen)
00766             elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
00767         pg_verifymbstr(plrv_sc, slen, false);
00768         rv = InputFunctionCall(&arg->typfunc,
00769                                plrv_sc,
00770                                arg->typioparam,
00771                                typmod);
00772     }
00773     PG_CATCH();
00774     {
00775         Py_XDECREF(plrv_bo);
00776         PG_RE_THROW();
00777     }
00778     PG_END_TRY();
00779 
00780     Py_XDECREF(plrv_bo);
00781 
00782     return rv;
00783 }
00784 
00785 static Datum
00786 PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
00787 {
00788     ArrayType  *array;
00789     int         i;
00790     Datum      *elems;
00791     bool       *nulls;
00792     int         len;
00793     int         lbs;
00794 
00795     Assert(plrv != Py_None);
00796 
00797     if (!PySequence_Check(plrv))
00798         PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");
00799 
00800     len = PySequence_Length(plrv);
00801     elems = palloc(sizeof(*elems) * len);
00802     nulls = palloc(sizeof(*nulls) * len);
00803 
00804     for (i = 0; i < len; i++)
00805     {
00806         PyObject   *obj = PySequence_GetItem(plrv, i);
00807 
00808         if (obj == Py_None)
00809             nulls[i] = true;
00810         else
00811         {
00812             nulls[i] = false;
00813 
00814             /*
00815              * We don't support arrays of row types yet, so the first argument
00816              * can be NULL.
00817              */
00818             elems[i] = arg->elm->func(arg->elm, -1, obj);
00819         }
00820         Py_XDECREF(obj);
00821     }
00822 
00823     lbs = 1;
00824     array = construct_md_array(elems, nulls, 1, &len, &lbs,
00825                                get_element_type(arg->typoid), arg->elm->typlen, arg->elm->typbyval, arg->elm->typalign);
00826     return PointerGetDatum(array);
00827 }
00828 
00829 
00830 static Datum
00831 PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
00832 {
00833     HeapTuple   typeTup;
00834 
00835     typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid));
00836     if (!HeapTupleIsValid(typeTup))
00837         elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
00838 
00839     PLy_output_datum_func2(&info->out.d, typeTup);
00840 
00841     ReleaseSysCache(typeTup);
00842     ReleaseTupleDesc(desc);
00843 
00844     return PLyObject_ToDatum(&info->out.d, info->out.d.typmod, string);
00845 }
00846 
00847 
00848 static Datum
00849 PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
00850 {
00851     HeapTuple   tuple;
00852     Datum      *values;
00853     bool       *nulls;
00854     volatile int i;
00855 
00856     Assert(PyMapping_Check(mapping));
00857 
00858     if (info->is_rowtype == 2)
00859         PLy_output_tuple_funcs(info, desc);
00860     Assert(info->is_rowtype == 1);
00861 
00862     /* Build tuple */
00863     values = palloc(sizeof(Datum) * desc->natts);
00864     nulls = palloc(sizeof(bool) * desc->natts);
00865     for (i = 0; i < desc->natts; ++i)
00866     {
00867         char       *key;
00868         PyObject   *volatile value;
00869         PLyObToDatum *att;
00870 
00871         if (desc->attrs[i]->attisdropped)
00872         {
00873             values[i] = (Datum) 0;
00874             nulls[i] = true;
00875             continue;
00876         }
00877 
00878         key = NameStr(desc->attrs[i]->attname);
00879         value = NULL;
00880         att = &info->out.r.atts[i];
00881         PG_TRY();
00882         {
00883             value = PyMapping_GetItemString(mapping, key);
00884             if (value == Py_None)
00885             {
00886                 values[i] = (Datum) NULL;
00887                 nulls[i] = true;
00888             }
00889             else if (value)
00890             {
00891                 values[i] = (att->func) (att, -1, value);
00892                 nulls[i] = false;
00893             }
00894             else
00895                 ereport(ERROR,
00896                         (errcode(ERRCODE_UNDEFINED_COLUMN),
00897                          errmsg("key \"%s\" not found in mapping", key),
00898                          errhint("To return null in a column, "
00899                                  "add the value None to the mapping with the key named after the column.")));
00900 
00901             Py_XDECREF(value);
00902             value = NULL;
00903         }
00904         PG_CATCH();
00905         {
00906             Py_XDECREF(value);
00907             PG_RE_THROW();
00908         }
00909         PG_END_TRY();
00910     }
00911 
00912     tuple = heap_form_tuple(desc, values, nulls);
00913     ReleaseTupleDesc(desc);
00914     pfree(values);
00915     pfree(nulls);
00916 
00917     return HeapTupleGetDatum(tuple);
00918 }
00919 
00920 
00921 static Datum
00922 PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
00923 {
00924     HeapTuple   tuple;
00925     Datum      *values;
00926     bool       *nulls;
00927     volatile int idx;
00928     volatile int i;
00929 
00930     Assert(PySequence_Check(sequence));
00931 
00932     /*
00933      * Check that sequence length is exactly same as PG tuple's. We actually
00934      * can ignore exceeding items or assume missing ones as null but to avoid
00935      * plpython developer's errors we are strict here
00936      */
00937     idx = 0;
00938     for (i = 0; i < desc->natts; i++)
00939     {
00940         if (!desc->attrs[i]->attisdropped)
00941             idx++;
00942     }
00943     if (PySequence_Length(sequence) != idx)
00944         ereport(ERROR,
00945                 (errcode(ERRCODE_DATATYPE_MISMATCH),
00946                  errmsg("length of returned sequence did not match number of columns in row")));
00947 
00948     if (info->is_rowtype == 2)
00949         PLy_output_tuple_funcs(info, desc);
00950     Assert(info->is_rowtype == 1);
00951 
00952     /* Build tuple */
00953     values = palloc(sizeof(Datum) * desc->natts);
00954     nulls = palloc(sizeof(bool) * desc->natts);
00955     idx = 0;
00956     for (i = 0; i < desc->natts; ++i)
00957     {
00958         PyObject   *volatile value;
00959         PLyObToDatum *att;
00960 
00961         if (desc->attrs[i]->attisdropped)
00962         {
00963             values[i] = (Datum) 0;
00964             nulls[i] = true;
00965             continue;
00966         }
00967 
00968         value = NULL;
00969         att = &info->out.r.atts[i];
00970         PG_TRY();
00971         {
00972             value = PySequence_GetItem(sequence, idx);
00973             Assert(value);
00974             if (value == Py_None)
00975             {
00976                 values[i] = (Datum) NULL;
00977                 nulls[i] = true;
00978             }
00979             else if (value)
00980             {
00981                 values[i] = (att->func) (att, -1, value);
00982                 nulls[i] = false;
00983             }
00984 
00985             Py_XDECREF(value);
00986             value = NULL;
00987         }
00988         PG_CATCH();
00989         {
00990             Py_XDECREF(value);
00991             PG_RE_THROW();
00992         }
00993         PG_END_TRY();
00994 
00995         idx++;
00996     }
00997 
00998     tuple = heap_form_tuple(desc, values, nulls);
00999     ReleaseTupleDesc(desc);
01000     pfree(values);
01001     pfree(nulls);
01002 
01003     return HeapTupleGetDatum(tuple);
01004 }
01005 
01006 
01007 static Datum
01008 PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object)
01009 {
01010     HeapTuple   tuple;
01011     Datum      *values;
01012     bool       *nulls;
01013     volatile int i;
01014 
01015     if (info->is_rowtype == 2)
01016         PLy_output_tuple_funcs(info, desc);
01017     Assert(info->is_rowtype == 1);
01018 
01019     /* Build tuple */
01020     values = palloc(sizeof(Datum) * desc->natts);
01021     nulls = palloc(sizeof(bool) * desc->natts);
01022     for (i = 0; i < desc->natts; ++i)
01023     {
01024         char       *key;
01025         PyObject   *volatile value;
01026         PLyObToDatum *att;
01027 
01028         if (desc->attrs[i]->attisdropped)
01029         {
01030             values[i] = (Datum) 0;
01031             nulls[i] = true;
01032             continue;
01033         }
01034 
01035         key = NameStr(desc->attrs[i]->attname);
01036         value = NULL;
01037         att = &info->out.r.atts[i];
01038         PG_TRY();
01039         {
01040             value = PyObject_GetAttrString(object, key);
01041             if (value == Py_None)
01042             {
01043                 values[i] = (Datum) NULL;
01044                 nulls[i] = true;
01045             }
01046             else if (value)
01047             {
01048                 values[i] = (att->func) (att, -1, value);
01049                 nulls[i] = false;
01050             }
01051             else
01052                 ereport(ERROR,
01053                         (errcode(ERRCODE_UNDEFINED_COLUMN),
01054                          errmsg("attribute \"%s\" does not exist in Python object", key),
01055                          errhint("To return null in a column, "
01056                            "let the returned object have an attribute named "
01057                                  "after column with value None.")));
01058 
01059             Py_XDECREF(value);
01060             value = NULL;
01061         }
01062         PG_CATCH();
01063         {
01064             Py_XDECREF(value);
01065             PG_RE_THROW();
01066         }
01067         PG_END_TRY();
01068     }
01069 
01070     tuple = heap_form_tuple(desc, values, nulls);
01071     ReleaseTupleDesc(desc);
01072     pfree(values);
01073     pfree(nulls);
01074 
01075     return HeapTupleGetDatum(tuple);
01076 }
01077 
01078 /*
01079  * This routine is a crock, and so is everyplace that calls it.  The problem
01080  * is that the cached form of plpython functions/queries is allocated permanently
01081  * (mostly via malloc()) and never released until backend exit.  Subsidiary
01082  * data structures such as fmgr info records therefore must live forever
01083  * as well.  A better implementation would store all this stuff in a per-
01084  * function memory context that could be reclaimed at need.  In the meantime,
01085  * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
01086  * it might allocate, and whatever the eventual function might allocate using
01087  * fn_mcxt, will live forever too.
01088  */
01089 static void
01090 perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
01091 {
01092     fmgr_info_cxt(functionId, finfo, TopMemoryContext);
01093 }