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

Generated by: LCOV version 1.13