LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_typeio.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 537 555 96.8 %
Date: 2020-05-25 05:06:35 Functions: 36 36 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13