LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_typeio.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 96.8 % 570 552 18 552
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 36 36 36
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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 *PLyLong_FromInt16(PLyDatumToOb *arg, Datum d);
      30                 : static PyObject *PLyLong_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 *PLyUnicode_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 PLyUnicode_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 CBC         585 : PLy_input_convert(PLyDatumToOb *arg, Datum val)
      81                 : {
      82                 :     PyObject   *result;
      83             585 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
      84             585 :     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             585 :     MemoryContextReset(scratch_context);
      99                 : 
     100             585 :     oldcontext = MemoryContextSwitchTo(scratch_context);
     101                 : 
     102             585 :     result = arg->func(arg, val);
     103                 : 
     104             585 :     MemoryContextSwitchTo(oldcontext);
     105                 : 
     106             585 :     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             557 : PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
     120                 : {
     121                 :     /* at outer level, we are not considering an array element */
     122             557 :     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             194 : PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
     134                 : {
     135                 :     PyObject   *dict;
     136             194 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
     137             194 :     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             194 :     MemoryContextReset(scratch_context);
     144                 : 
     145             194 :     oldcontext = MemoryContextSwitchTo(scratch_context);
     146                 : 
     147             194 :     dict = PLyDict_FromTuple(arg, tuple, desc, include_generated);
     148                 : 
     149             194 :     MemoryContextSwitchTo(oldcontext);
     150                 : 
     151             194 :     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             185 : 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             185 :     Assert(arg->func == PLyDict_FromComposite);
     170                 : 
     171                 :     /* Save pointer to tupdesc, but only if this is an anonymous record type */
     172             185 :     if (arg->typoid == RECORDOID && arg->typmod < 0)
     173              90 :         arg->u.tuple.recdesc = desc;
     174                 : 
     175                 :     /* (Re)allocate atts array as needed */
     176             185 :     if (arg->u.tuple.natts != desc->natts)
     177                 :     {
     178             107 :         if (arg->u.tuple.atts)
     179               1 :             pfree(arg->u.tuple.atts);
     180             107 :         arg->u.tuple.natts = desc->natts;
     181             107 :         arg->u.tuple.atts = (PLyDatumToOb *)
     182             107 :             MemoryContextAllocZero(arg->mcxt,
     183             107 :                                    desc->natts * sizeof(PLyDatumToOb));
     184                 :     }
     185                 : 
     186                 :     /* Fill the atts entries, except for dropped columns */
     187             589 :     for (i = 0; i < desc->natts; i++)
     188                 :     {
     189             404 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
     190             404 :         PLyDatumToOb *att = &arg->u.tuple.atts[i];
     191                 : 
     192             404 :         if (attr->attisdropped)
     193               3 :             continue;
     194                 : 
     195             401 :         if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
     196             223 :             continue;           /* already set up this entry */
     197                 : 
     198             178 :         PLy_input_setup_func(att, arg->mcxt,
     199                 :                              attr->atttypid, attr->atttypmod,
     200                 :                              proc);
     201                 :     }
     202             185 : }
     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             151 : 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             151 :     Assert(arg->func == PLyObject_ToComposite);
     220                 : 
     221                 :     /* Save pointer to tupdesc, but only if this is an anonymous record type */
     222             151 :     if (arg->typoid == RECORDOID && arg->typmod < 0)
     223 UBC           0 :         arg->u.tuple.recdesc = desc;
     224                 : 
     225                 :     /* (Re)allocate atts array as needed */
     226 CBC         151 :     if (arg->u.tuple.natts != desc->natts)
     227                 :     {
     228              72 :         if (arg->u.tuple.atts)
     229               3 :             pfree(arg->u.tuple.atts);
     230              72 :         arg->u.tuple.natts = desc->natts;
     231              72 :         arg->u.tuple.atts = (PLyObToDatum *)
     232              72 :             MemoryContextAllocZero(arg->mcxt,
     233              72 :                                    desc->natts * sizeof(PLyObToDatum));
     234                 :     }
     235                 : 
     236                 :     /* Fill the atts entries, except for dropped columns */
     237             492 :     for (i = 0; i < desc->natts; i++)
     238                 :     {
     239             341 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
     240             341 :         PLyObToDatum *att = &arg->u.tuple.atts[i];
     241                 : 
     242             341 :         if (attr->attisdropped)
     243              28 :             continue;
     244                 : 
     245             313 :         if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
     246             160 :             continue;           /* already set up this entry */
     247                 : 
     248             153 :         PLy_output_setup_func(att, arg->mcxt,
     249                 :                               attr->atttypid, attr->atttypmod,
     250                 :                               proc);
     251                 :     }
     252             151 : }
     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              74 : PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc)
     261                 : {
     262                 :     /* Makes no sense unless RECORD */
     263              74 :     Assert(arg->typoid == RECORDOID);
     264              74 :     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              74 :     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              74 :     arg->typmod = desc->tdtypmod;
     279              74 :     if (arg->u.tuple.recdesc &&
     280              57 :         arg->u.tuple.recdesc->tdtypmod != arg->typmod)
     281               9 :         arg->u.tuple.recdesc = NULL;
     282                 : 
     283                 :     /* Update derived data if necessary */
     284              74 :     PLy_output_setup_tuple(arg, desc, proc);
     285              74 : }
     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             452 : 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             452 :     check_stack_depth();
     306                 : 
     307             452 :     arg->typoid = typeOid;
     308             452 :     arg->typmod = typmod;
     309             452 :     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             452 :     if (typeOid != RECORDOID)
     317                 :     {
     318             435 :         typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
     319             435 :         typtype = typentry->typtype;
     320             435 :         arg->typbyval = typentry->typbyval;
     321             435 :         arg->typlen = typentry->typlen;
     322             435 :         arg->typalign = typentry->typalign;
     323                 :     }
     324                 :     else
     325                 :     {
     326              17 :         typentry = NULL;
     327              17 :         typtype = TYPTYPE_COMPOSITE;
     328                 :         /* hard-wired knowledge about type RECORD: */
     329              17 :         arg->typbyval = false;
     330              17 :         arg->typlen = -1;
     331              17 :         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             452 :     if (typtype == TYPTYPE_DOMAIN)
     342                 :     {
     343                 :         /* Domain */
     344              14 :         arg->func = PLyObject_ToDomain;
     345              14 :         arg->u.domain.domain_info = NULL;
     346                 :         /* Recursively set up conversion info for the element type */
     347              14 :         arg->u.domain.base = (PLyObToDatum *)
     348              14 :             MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
     349              14 :         PLy_output_setup_func(arg->u.domain.base, arg_mcxt,
     350                 :                               typentry->domainBaseType,
     351                 :                               typentry->domainBaseTypmod,
     352                 :                               proc);
     353                 :     }
     354             438 :     else if (typentry &&
     355             421 :              IsTrueArrayType(typentry))
     356                 :     {
     357                 :         /* Standard array */
     358              31 :         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              31 :         arg->u.array.elmbasetype = getBaseType(typentry->typelem);
     362                 :         /* Recursively set up conversion info for the element type */
     363              31 :         arg->u.array.elm = (PLyObToDatum *)
     364              31 :             MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum));
     365              31 :         PLy_output_setup_func(arg->u.array.elm, arg_mcxt,
     366                 :                               typentry->typelem, typmod,
     367                 :                               proc);
     368                 :     }
     369             407 :     else if ((trfuncid = get_transform_tosql(typeOid,
     370                 :                                              proc->langid,
     371                 :                                              proc->trftypes)))
     372                 :     {
     373              11 :         arg->func = PLyObject_ToTransform;
     374              11 :         fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
     375                 :     }
     376             396 :     else if (typtype == TYPTYPE_COMPOSITE)
     377                 :     {
     378                 :         /* Named composite type, or RECORD */
     379              71 :         arg->func = PLyObject_ToComposite;
     380                 :         /* We'll set up the per-field data later */
     381              71 :         arg->u.tuple.recdesc = NULL;
     382              71 :         arg->u.tuple.typentry = typentry;
     383              71 :         arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
     384              71 :         arg->u.tuple.atts = NULL;
     385              71 :         arg->u.tuple.natts = 0;
     386                 :         /* Mark this invalid till needed, too */
     387              71 :         arg->u.tuple.recinfunc.fn_oid = InvalidOid;
     388                 :     }
     389                 :     else
     390                 :     {
     391                 :         /* Scalar type, but we have a couple of special cases */
     392             325 :         switch (typeOid)
     393                 :         {
     394              14 :             case BOOLOID:
     395              14 :                 arg->func = PLyObject_ToBool;
     396              14 :                 break;
     397               6 :             case BYTEAOID:
     398               6 :                 arg->func = PLyObject_ToBytea;
     399               6 :                 break;
     400             305 :             default:
     401             305 :                 arg->func = PLyObject_ToScalar;
     402             305 :                 getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam);
     403             305 :                 fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt);
     404             305 :                 break;
     405                 :         }
     406                 :     }
     407             452 : }
     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             456 : 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             456 :     check_stack_depth();
     429                 : 
     430             456 :     arg->typoid = typeOid;
     431             456 :     arg->typmod = typmod;
     432             456 :     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             456 :     if (typeOid != RECORDOID)
     440                 :     {
     441             380 :         typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO);
     442             380 :         typtype = typentry->typtype;
     443             380 :         arg->typbyval = typentry->typbyval;
     444             380 :         arg->typlen = typentry->typlen;
     445             380 :         arg->typalign = typentry->typalign;
     446                 :     }
     447                 :     else
     448                 :     {
     449              76 :         typentry = NULL;
     450              76 :         typtype = TYPTYPE_COMPOSITE;
     451                 :         /* hard-wired knowledge about type RECORD: */
     452              76 :         arg->typbyval = false;
     453              76 :         arg->typlen = -1;
     454              76 :         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             456 :     if (typtype == TYPTYPE_DOMAIN)
     465                 :     {
     466                 :         /* Domain --- we don't care, just recurse down to the base type */
     467               9 :         PLy_input_setup_func(arg, arg_mcxt,
     468                 :                              typentry->domainBaseType,
     469                 :                              typentry->domainBaseTypmod,
     470                 :                              proc);
     471                 :     }
     472             447 :     else if (typentry &&
     473             371 :              IsTrueArrayType(typentry))
     474                 :     {
     475                 :         /* Standard array */
     476              13 :         arg->func = PLyList_FromArray;
     477                 :         /* Recursively set up conversion info for the element type */
     478              13 :         arg->u.array.elm = (PLyDatumToOb *)
     479              13 :             MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb));
     480              13 :         PLy_input_setup_func(arg->u.array.elm, arg_mcxt,
     481                 :                              typentry->typelem, typmod,
     482                 :                              proc);
     483                 :     }
     484             434 :     else if ((trfuncid = get_transform_fromsql(typeOid,
     485                 :                                                proc->langid,
     486                 :                                                proc->trftypes)))
     487                 :     {
     488              16 :         arg->func = PLyObject_FromTransform;
     489              16 :         fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt);
     490                 :     }
     491             418 :     else if (typtype == TYPTYPE_COMPOSITE)
     492                 :     {
     493                 :         /* Named composite type, or RECORD */
     494             116 :         arg->func = PLyDict_FromComposite;
     495                 :         /* We'll set up the per-field data later */
     496             116 :         arg->u.tuple.recdesc = NULL;
     497             116 :         arg->u.tuple.typentry = typentry;
     498             116 :         arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
     499             116 :         arg->u.tuple.atts = NULL;
     500             116 :         arg->u.tuple.natts = 0;
     501                 :     }
     502                 :     else
     503                 :     {
     504                 :         /* Scalar type, but we have a couple of special cases */
     505             302 :         switch (typeOid)
     506                 :         {
     507              14 :             case BOOLOID:
     508              14 :                 arg->func = PLyBool_FromBool;
     509              14 :                 break;
     510               1 :             case FLOAT4OID:
     511               1 :                 arg->func = PLyFloat_FromFloat4;
     512               1 :                 break;
     513               1 :             case FLOAT8OID:
     514               1 :                 arg->func = PLyFloat_FromFloat8;
     515               1 :                 break;
     516               1 :             case NUMERICOID:
     517               1 :                 arg->func = PLyDecimal_FromNumeric;
     518               1 :                 break;
     519               4 :             case INT2OID:
     520               4 :                 arg->func = PLyLong_FromInt16;
     521               4 :                 break;
     522             141 :             case INT4OID:
     523             141 :                 arg->func = PLyLong_FromInt32;
     524             141 :                 break;
     525               5 :             case INT8OID:
     526               5 :                 arg->func = PLyLong_FromInt64;
     527               5 :                 break;
     528               1 :             case OIDOID:
     529               1 :                 arg->func = PLyLong_FromOid;
     530               1 :                 break;
     531               7 :             case BYTEAOID:
     532               7 :                 arg->func = PLyBytes_FromBytea;
     533               7 :                 break;
     534             127 :             default:
     535             127 :                 arg->func = PLyUnicode_FromScalar;
     536             127 :                 getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
     537             127 :                 fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
     538             127 :                 break;
     539                 :         }
     540                 :     }
     541             456 : }
     542                 : 
     543                 : 
     544                 : /*
     545                 :  * Special-purpose input converters.
     546                 :  */
     547                 : 
     548                 : static PyObject *
     549             121 : PLyBool_FromBool(PLyDatumToOb *arg, Datum d)
     550                 : {
     551             121 :     if (DatumGetBool(d))
     552              26 :         Py_RETURN_TRUE;
     553              95 :     Py_RETURN_FALSE;
     554                 : }
     555                 : 
     556                 : static PyObject *
     557               3 : PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d)
     558                 : {
     559               3 :     return PyFloat_FromDouble(DatumGetFloat4(d));
     560                 : }
     561                 : 
     562                 : static PyObject *
     563               4 : PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d)
     564                 : {
     565               4 :     return PyFloat_FromDouble(DatumGetFloat8(d));
     566                 : }
     567                 : 
     568                 : static PyObject *
     569               7 : 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               7 :     if (!decimal_constructor)
     577                 :     {
     578                 :         PyObject   *decimal_module;
     579                 : 
     580               1 :         decimal_module = PyImport_ImportModule("cdecimal");
     581               1 :         if (!decimal_module)
     582                 :         {
     583               1 :             PyErr_Clear();
     584               1 :             decimal_module = PyImport_ImportModule("decimal");
     585                 :         }
     586               1 :         if (!decimal_module)
     587 UBC           0 :             PLy_elog(ERROR, "could not import a module for Decimal constructor");
     588                 : 
     589 CBC           1 :         decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
     590               1 :         if (!decimal_constructor)
     591 UBC           0 :             PLy_elog(ERROR, "no Decimal attribute in module");
     592                 :     }
     593                 : 
     594 CBC           7 :     str = DatumGetCString(DirectFunctionCall1(numeric_out, d));
     595               7 :     pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
     596               7 :     if (!pyvalue)
     597 UBC           0 :         PLy_elog(ERROR, "conversion from numeric to Decimal failed");
     598                 : 
     599 CBC           7 :     return pyvalue;
     600                 : }
     601                 : 
     602                 : static PyObject *
     603               7 : PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
     604                 : {
     605               7 :     return PyLong_FromLong(DatumGetInt16(d));
     606                 : }
     607                 : 
     608                 : static PyObject *
     609             396 : PLyLong_FromInt32(PLyDatumToOb *arg, Datum d)
     610                 : {
     611             396 :     return PyLong_FromLong(DatumGetInt32(d));
     612                 : }
     613                 : 
     614                 : static PyObject *
     615              15 : PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
     616                 : {
     617              15 :     return PyLong_FromLongLong(DatumGetInt64(d));
     618                 : }
     619                 : 
     620                 : static PyObject *
     621               2 : PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
     622                 : {
     623               2 :     return PyLong_FromUnsignedLong(DatumGetObjectId(d));
     624                 : }
     625                 : 
     626                 : static PyObject *
     627              11 : PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
     628                 : {
     629              11 :     text       *txt = DatumGetByteaPP(d);
     630              11 :     char       *str = VARDATA_ANY(txt);
     631              11 :     size_t      size = VARSIZE_ANY_EXHDR(txt);
     632                 : 
     633              11 :     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             482 : PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d)
     642                 : {
     643             482 :     char       *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
     644             482 :     PyObject   *r = PLyUnicode_FromString(x);
     645                 : 
     646             482 :     pfree(x);
     647             482 :     return r;
     648                 : }
     649                 : 
     650                 : /*
     651                 :  * Convert using a from-SQL transform function.
     652                 :  */
     653                 : static PyObject *
     654              35 : PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
     655                 : {
     656                 :     Datum       t;
     657                 : 
     658              35 :     t = FunctionCall1(&arg->u.transform.typtransform, d);
     659              35 :     return (PyObject *) DatumGetPointer(t);
     660                 : }
     661                 : 
     662                 : /*
     663                 :  * Convert a SQL array to a Python list.
     664                 :  */
     665                 : static PyObject *
     666              21 : PLyList_FromArray(PLyDatumToOb *arg, Datum d)
     667                 : {
     668              21 :     ArrayType  *array = DatumGetArrayTypeP(d);
     669              21 :     PLyDatumToOb *elm = arg->u.array.elm;
     670                 :     int         ndim;
     671                 :     int        *dims;
     672                 :     char       *dataptr;
     673                 :     bits8      *bitmap;
     674                 :     int         bitmask;
     675                 : 
     676              21 :     if (ARR_NDIM(array) == 0)
     677               1 :         return PyList_New(0);
     678                 : 
     679                 :     /* Array dimensions and left bounds */
     680              20 :     ndim = ARR_NDIM(array);
     681              20 :     dims = ARR_DIMS(array);
     682              20 :     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              20 :     dataptr = ARR_DATA_PTR(array);
     698              20 :     bitmap = ARR_NULLBITMAP(array);
     699              20 :     bitmask = 1;
     700                 : 
     701              20 :     return PLyList_FromArray_recurse(elm, dims, ndim, 0,
     702                 :                                      &dataptr, &bitmap, &bitmask);
     703                 : }
     704                 : 
     705                 : static PyObject *
     706              48 : 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              48 :     list = PyList_New(dims[dim]);
     713              48 :     if (!list)
     714 UBC           0 :         return NULL;
     715                 : 
     716 CBC          48 :     if (dim < ndim - 1)
     717                 :     {
     718                 :         /* Outer dimension. Recurse for each inner slice. */
     719              42 :         for (i = 0; i < dims[dim]; i++)
     720                 :         {
     721                 :             PyObject   *sublist;
     722                 : 
     723              28 :             sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
     724                 :                                                 dataptr_p, bitmap_p, bitmask_p);
     725              28 :             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              34 :         char       *dataptr = *dataptr_p;
     735              34 :         bits8      *bitmap = *bitmap_p;
     736              34 :         int         bitmask = *bitmask_p;
     737                 : 
     738             120 :         for (i = 0; i < dims[dim]; i++)
     739                 :         {
     740                 :             /* checking for NULL */
     741              86 :             if (bitmap && (*bitmap & bitmask) == 0)
     742                 :             {
     743              14 :                 Py_INCREF(Py_None);
     744              14 :                 PyList_SET_ITEM(list, i, Py_None);
     745                 :             }
     746                 :             else
     747                 :             {
     748                 :                 Datum       itemvalue;
     749                 : 
     750              72 :                 itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
     751              72 :                 PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
     752              72 :                 dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
     753              72 :                 dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
     754                 :             }
     755                 : 
     756                 :             /* advance bitmap pointer if any */
     757              86 :             if (bitmap)
     758                 :             {
     759              52 :                 bitmask <<= 1;
     760              52 :                 if (bitmask == 0x100 /* (1<<8) */ )
     761                 :                 {
     762               4 :                     bitmap++;
     763               4 :                     bitmask = 1;
     764                 :                 }
     765                 :             }
     766                 :         }
     767                 : 
     768              34 :         *dataptr_p = dataptr;
     769              34 :         *bitmap_p = bitmap;
     770              34 :         *bitmask_p = bitmask;
     771                 :     }
     772                 : 
     773              48 :     return list;
     774                 : }
     775                 : 
     776                 : /*
     777                 :  * Convert a composite SQL value to a Python dict.
     778                 :  */
     779                 : static PyObject *
     780              49 : 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              49 :     td = DatumGetHeapTupleHeader(d);
     790                 :     /* Extract rowtype info and find a tupdesc */
     791              49 :     tupType = HeapTupleHeaderGetTypeId(td);
     792              49 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
     793              49 :     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
     794                 : 
     795                 :     /* Set up I/O funcs if not done yet */
     796              49 :     PLy_input_setup_tuple(arg, tupdesc,
     797              49 :                           PLy_current_execution_context()->curr_proc);
     798                 : 
     799                 :     /* Build a temporary HeapTuple control structure */
     800              49 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
     801              49 :     tmptup.t_data = td;
     802                 : 
     803              49 :     dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
     804                 : 
     805              49 :     ReleaseTupleDesc(tupdesc);
     806                 : 
     807              49 :     return dict;
     808                 : }
     809                 : 
     810                 : /*
     811                 :  * Transform a tuple into a Python dict object.
     812                 :  */
     813                 : static PyObject *
     814             243 : 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             243 :     Assert(desc->natts == arg->u.tuple.natts);
     820                 : 
     821             243 :     dict = PyDict_New();
     822             243 :     if (dict == NULL)
     823 UBC           0 :         return NULL;
     824                 : 
     825 CBC         243 :     PG_TRY();
     826                 :     {
     827                 :         int         i;
     828                 : 
     829             758 :         for (i = 0; i < arg->u.tuple.natts; i++)
     830                 :         {
     831             515 :             PLyDatumToOb *att = &arg->u.tuple.atts[i];
     832             515 :             Form_pg_attribute attr = TupleDescAttr(desc, i);
     833                 :             char       *key;
     834                 :             Datum       vattr;
     835                 :             bool        is_null;
     836                 :             PyObject   *value;
     837                 : 
     838             515 :             if (attr->attisdropped)
     839               6 :                 continue;
     840                 : 
     841             512 :             if (attr->attgenerated)
     842                 :             {
     843                 :                 /* don't include unless requested */
     844               9 :                 if (!include_generated)
     845               3 :                     continue;
     846                 :             }
     847                 : 
     848             509 :             key = NameStr(attr->attname);
     849             509 :             vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
     850                 : 
     851             509 :             if (is_null)
     852              13 :                 PyDict_SetItemString(dict, key, Py_None);
     853                 :             else
     854                 :             {
     855             496 :                 value = att->func(att, vattr);
     856             496 :                 PyDict_SetItemString(dict, key, value);
     857             496 :                 Py_DECREF(value);
     858                 :             }
     859                 :         }
     860                 :     }
     861 UBC           0 :     PG_CATCH();
     862                 :     {
     863               0 :         Py_DECREF(dict);
     864               0 :         PG_RE_THROW();
     865                 :     }
     866 CBC         243 :     PG_END_TRY();
     867                 : 
     868             243 :     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              23 : PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv,
     879                 :                  bool *isnull, bool inarray)
     880                 : {
     881              23 :     if (plrv == Py_None)
     882                 :     {
     883               1 :         *isnull = true;
     884               1 :         return (Datum) 0;
     885                 :     }
     886              22 :     *isnull = false;
     887              22 :     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              11 : PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
     897                 :                   bool *isnull, bool inarray)
     898                 : {
     899              11 :     PyObject   *volatile plrv_so = NULL;
     900              11 :     Datum       rv = (Datum) 0;
     901                 : 
     902              11 :     if (plrv == Py_None)
     903                 :     {
     904               3 :         *isnull = true;
     905               3 :         return (Datum) 0;
     906                 :     }
     907               8 :     *isnull = false;
     908                 : 
     909               8 :     plrv_so = PyObject_Bytes(plrv);
     910               8 :     if (!plrv_so)
     911 UBC           0 :         PLy_elog(ERROR, "could not create bytes representation of Python object");
     912                 : 
     913 CBC           8 :     PG_TRY();
     914                 :     {
     915               8 :         char       *plrv_sc = PyBytes_AsString(plrv_so);
     916               8 :         size_t      len = PyBytes_Size(plrv_so);
     917               8 :         size_t      size = len + VARHDRSZ;
     918               8 :         bytea      *result = palloc(size);
     919                 : 
     920               8 :         SET_VARSIZE(result, size);
     921               8 :         memcpy(VARDATA(result), plrv_sc, len);
     922               8 :         rv = PointerGetDatum(result);
     923                 :     }
     924 UBC           0 :     PG_FINALLY();
     925                 :     {
     926 CBC           8 :         Py_XDECREF(plrv_so);
     927                 :     }
     928               8 :     PG_END_TRY();
     929                 : 
     930               8 :     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             289 : PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
     941                 :                       bool *isnull, bool inarray)
     942                 : {
     943                 :     Datum       rv;
     944                 :     TupleDesc   desc;
     945                 : 
     946             289 :     if (plrv == Py_None)
     947                 :     {
     948              21 :         *isnull = true;
     949              21 :         return (Datum) 0;
     950                 :     }
     951             268 :     *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             268 :     if (PyUnicode_Check(plrv))
     958              18 :         return PLyUnicode_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             250 :     if (arg->typoid != RECORDOID)
     967                 :     {
     968             125 :         desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
     969                 :         /* We should have the descriptor of the type's typcache entry */
     970             125 :         Assert(desc == arg->u.tuple.typentry->tupDesc);
     971                 :         /* Detect change of descriptor, update cache if needed */
     972             125 :         if (arg->u.tuple.tupdescid != arg->u.tuple.typentry->tupDesc_identifier)
     973                 :         {
     974              31 :             PLy_output_setup_tuple(arg, desc,
     975              31 :                                    PLy_current_execution_context()->curr_proc);
     976              31 :             arg->u.tuple.tupdescid = arg->u.tuple.typentry->tupDesc_identifier;
     977                 :         }
     978                 :     }
     979                 :     else
     980                 :     {
     981             125 :         desc = arg->u.tuple.recdesc;
     982             125 :         if (desc == NULL)
     983                 :         {
     984              26 :             desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);
     985              26 :             arg->u.tuple.recdesc = desc;
     986                 :         }
     987                 :         else
     988                 :         {
     989                 :             /* Pin descriptor to match unpin below */
     990              99 :             PinTupleDesc(desc);
     991                 :         }
     992                 :     }
     993                 : 
     994                 :     /* Simple sanity check on our caching */
     995             250 :     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             250 :     if (PySequence_Check(plrv))
    1002                 :         /* composite type as sequence (tuple, list etc) */
    1003             132 :         rv = PLySequence_ToComposite(arg, desc, plrv);
    1004             118 :     else if (PyMapping_Check(plrv))
    1005                 :         /* composite type as mapping (currently only dict) */
    1006              93 :         rv = PLyMapping_ToComposite(arg, desc, plrv);
    1007                 :     else
    1008                 :         /* returned as smth, must provide method __getattr__(name) */
    1009              25 :         rv = PLyGenericObject_ToComposite(arg, desc, plrv, inarray);
    1010                 : 
    1011             241 :     ReleaseTupleDesc(desc);
    1012                 : 
    1013             241 :     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            1570 : PLyObject_AsString(PyObject *plrv)
    1024                 : {
    1025                 :     PyObject   *plrv_bo;
    1026                 :     char       *plrv_sc;
    1027                 :     size_t      plen;
    1028                 :     size_t      slen;
    1029                 : 
    1030            1570 :     if (PyUnicode_Check(plrv))
    1031             333 :         plrv_bo = PLyUnicode_Bytes(plrv);
    1032            1237 :     else if (PyFloat_Check(plrv))
    1033                 :     {
    1034                 :         /* use repr() for floats, str() is lossy */
    1035               7 :         PyObject   *s = PyObject_Repr(plrv);
    1036                 : 
    1037               7 :         plrv_bo = PLyUnicode_Bytes(s);
    1038               7 :         Py_XDECREF(s);
    1039                 :     }
    1040                 :     else
    1041                 :     {
    1042            1230 :         PyObject   *s = PyObject_Str(plrv);
    1043                 : 
    1044            1230 :         plrv_bo = PLyUnicode_Bytes(s);
    1045            1230 :         Py_XDECREF(s);
    1046                 :     }
    1047            1570 :     if (!plrv_bo)
    1048 UBC           0 :         PLy_elog(ERROR, "could not create string representation of Python object");
    1049                 : 
    1050 CBC        1570 :     plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
    1051            1570 :     plen = PyBytes_Size(plrv_bo);
    1052            1570 :     slen = strlen(plrv_sc);
    1053                 : 
    1054            1570 :     Py_XDECREF(plrv_bo);
    1055                 : 
    1056            1570 :     if (slen < plen)
    1057 UBC           0 :         ereport(ERROR,
    1058                 :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1059                 :                  errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
    1060 CBC        1570 :     else if (slen > plen)
    1061 UBC           0 :         elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
    1062 CBC        1570 :     pg_verifymbstr(plrv_sc, slen, false);
    1063                 : 
    1064            1570 :     return plrv_sc;
    1065                 : }
    1066                 : 
    1067                 : 
    1068                 : /*
    1069                 :  * Generic output conversion function: convert PyObject to cstring and
    1070                 :  * cstring into PostgreSQL type.
    1071                 :  */
    1072                 : static Datum
    1073            1588 : PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv,
    1074                 :                    bool *isnull, bool inarray)
    1075                 : {
    1076                 :     char       *str;
    1077                 : 
    1078            1588 :     if (plrv == Py_None)
    1079                 :     {
    1080              97 :         *isnull = true;
    1081              97 :         return (Datum) 0;
    1082                 :     }
    1083            1491 :     *isnull = false;
    1084                 : 
    1085            1491 :     str = PLyObject_AsString(plrv);
    1086                 : 
    1087            1491 :     return InputFunctionCall(&arg->u.scalar.typfunc,
    1088                 :                              str,
    1089                 :                              arg->u.scalar.typioparam,
    1090                 :                              arg->typmod);
    1091                 : }
    1092                 : 
    1093                 : 
    1094                 : /*
    1095                 :  * Convert to a domain type.
    1096                 :  */
    1097                 : static Datum
    1098              29 : PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv,
    1099                 :                    bool *isnull, bool inarray)
    1100                 : {
    1101                 :     Datum       result;
    1102              29 :     PLyObToDatum *base = arg->u.domain.base;
    1103                 : 
    1104              29 :     result = base->func(base, plrv, isnull, inarray);
    1105              27 :     domain_check(result, *isnull, arg->typoid,
    1106                 :                  &arg->u.domain.domain_info, arg->mcxt);
    1107              16 :     return result;
    1108                 : }
    1109                 : 
    1110                 : 
    1111                 : /*
    1112                 :  * Convert using a to-SQL transform function.
    1113                 :  */
    1114                 : static Datum
    1115              30 : PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv,
    1116                 :                       bool *isnull, bool inarray)
    1117                 : {
    1118              30 :     if (plrv == Py_None)
    1119                 :     {
    1120               1 :         *isnull = true;
    1121               1 :         return (Datum) 0;
    1122                 :     }
    1123              29 :     *isnull = false;
    1124              29 :     return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
    1125                 : }
    1126                 : 
    1127                 : 
    1128                 : /*
    1129                 :  * Convert Python sequence to SQL array.
    1130                 :  */
    1131                 : static Datum
    1132              50 : PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
    1133                 :                     bool *isnull, bool inarray)
    1134                 : {
    1135                 :     ArrayType  *array;
    1136                 :     int         i;
    1137                 :     Datum      *elems;
    1138                 :     bool       *nulls;
    1139                 :     int64       len;
    1140                 :     int         ndim;
    1141                 :     int         dims[MAXDIM];
    1142                 :     int         lbs[MAXDIM];
    1143                 :     int         currelem;
    1144              50 :     PyObject   *pyptr = plrv;
    1145                 :     PyObject   *next;
    1146                 : 
    1147              50 :     if (plrv == Py_None)
    1148                 :     {
    1149               2 :         *isnull = true;
    1150               2 :         return (Datum) 0;
    1151                 :     }
    1152              48 :     *isnull = false;
    1153                 : 
    1154                 :     /*
    1155                 :      * Determine the number of dimensions, and their sizes.
    1156                 :      */
    1157              48 :     ndim = 0;
    1158              48 :     len = 1;
    1159                 : 
    1160              48 :     Py_INCREF(plrv);
    1161                 : 
    1162                 :     for (;;)
    1163                 :     {
    1164             122 :         if (!PyList_Check(pyptr))
    1165              46 :             break;
    1166                 : 
    1167              76 :         if (ndim == MAXDIM)
    1168               1 :             ereport(ERROR,
    1169                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1170                 :                      errmsg("number of array dimensions exceeds the maximum allowed (%d)",
    1171                 :                             MAXDIM)));
    1172                 : 
    1173              75 :         dims[ndim] = PySequence_Length(pyptr);
    1174              75 :         if (dims[ndim] < 0)
    1175 UBC           0 :             PLy_elog(ERROR, "could not determine sequence length for function return value");
    1176                 : 
    1177 CBC          75 :         if (dims[ndim] > MaxAllocSize)
    1178 UBC           0 :             ereport(ERROR,
    1179                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1180                 :                      errmsg("array size exceeds the maximum allowed")));
    1181                 : 
    1182 CBC          75 :         len *= dims[ndim];
    1183              75 :         if (len > MaxAllocSize)
    1184 UBC           0 :             ereport(ERROR,
    1185                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1186                 :                      errmsg("array size exceeds the maximum allowed")));
    1187                 : 
    1188 CBC          75 :         if (dims[ndim] == 0)
    1189                 :         {
    1190                 :             /* empty sequence */
    1191               1 :             break;
    1192                 :         }
    1193                 : 
    1194              74 :         ndim++;
    1195                 : 
    1196              74 :         next = PySequence_GetItem(pyptr, 0);
    1197              74 :         Py_XDECREF(pyptr);
    1198              74 :         pyptr = next;
    1199                 :     }
    1200              47 :     Py_XDECREF(pyptr);
    1201                 : 
    1202                 :     /*
    1203                 :      * Check for zero dimensions. This happens if the object is a tuple or a
    1204                 :      * string, rather than a list, or is not a sequence at all. We don't map
    1205                 :      * tuples or strings to arrays in general, but in the first level, be
    1206                 :      * lenient, for historical reasons. So if the object is a sequence of any
    1207                 :      * kind, treat it as a one-dimensional array.
    1208                 :      */
    1209              47 :     if (ndim == 0)
    1210                 :     {
    1211               6 :         if (!PySequence_Check(plrv))
    1212               3 :             ereport(ERROR,
    1213                 :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    1214                 :                      errmsg("return value of function with array return type is not a Python sequence")));
    1215                 : 
    1216               3 :         ndim = 1;
    1217               3 :         len = dims[0] = PySequence_Length(plrv);
    1218                 :     }
    1219                 : 
    1220                 :     /*
    1221                 :      * Traverse the Python lists, in depth-first order, and collect all the
    1222                 :      * elements at the bottom level into 'elems'/'nulls' arrays.
    1223                 :      */
    1224              44 :     elems = palloc(sizeof(Datum) * len);
    1225              44 :     nulls = palloc(sizeof(bool) * len);
    1226              44 :     currelem = 0;
    1227              44 :     PLySequence_ToArray_recurse(arg->u.array.elm, plrv,
    1228                 :                                 dims, ndim, 0,
    1229                 :                                 elems, nulls, &currelem);
    1230                 : 
    1231              97 :     for (i = 0; i < ndim; i++)
    1232              60 :         lbs[i] = 1;
    1233                 : 
    1234              37 :     array = construct_md_array(elems,
    1235                 :                                nulls,
    1236                 :                                ndim,
    1237                 :                                dims,
    1238                 :                                lbs,
    1239                 :                                arg->u.array.elmbasetype,
    1240              37 :                                arg->u.array.elm->typlen,
    1241              37 :                                arg->u.array.elm->typbyval,
    1242              37 :                                arg->u.array.elm->typalign);
    1243                 : 
    1244              37 :     return PointerGetDatum(array);
    1245                 : }
    1246                 : 
    1247                 : /*
    1248                 :  * Helper function for PLySequence_ToArray. Traverse a Python list of lists in
    1249                 :  * depth-first order, storing the elements in 'elems'.
    1250                 :  */
    1251                 : static void
    1252             232 : PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
    1253                 :                             int *dims, int ndim, int dim,
    1254                 :                             Datum *elems, bool *nulls, int *currelem)
    1255                 : {
    1256                 :     int         i;
    1257                 : 
    1258             232 :     if (PySequence_Length(list) != dims[dim])
    1259               1 :         ereport(ERROR,
    1260                 :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1261                 :                  errmsg("wrong length of inner sequence: has length %d, but %d was expected",
    1262                 :                         (int) PySequence_Length(list), dims[dim]),
    1263                 :                  (errdetail("To construct a multidimensional array, the inner sequences must all have the same length."))));
    1264                 : 
    1265             231 :     if (dim < ndim - 1)
    1266                 :     {
    1267             239 :         for (i = 0; i < dims[dim]; i++)
    1268                 :         {
    1269             188 :             PyObject   *sublist = PySequence_GetItem(list, i);
    1270                 : 
    1271             188 :             PLySequence_ToArray_recurse(elm, sublist, dims, ndim, dim + 1,
    1272                 :                                         elems, nulls, currelem);
    1273             184 :             Py_XDECREF(sublist);
    1274                 :         }
    1275                 :     }
    1276                 :     else
    1277                 :     {
    1278            1077 :         for (i = 0; i < dims[dim]; i++)
    1279                 :         {
    1280             907 :             PyObject   *obj = PySequence_GetItem(list, i);
    1281                 : 
    1282             907 :             elems[*currelem] = elm->func(elm, obj, &nulls[*currelem], true);
    1283             901 :             Py_XDECREF(obj);
    1284             901 :             (*currelem)++;
    1285                 :         }
    1286                 :     }
    1287             221 : }
    1288                 : 
    1289                 : 
    1290                 : /*
    1291                 :  * Convert a Python string to composite, using record_in.
    1292                 :  */
    1293                 : static Datum
    1294              18 : PLyUnicode_ToComposite(PLyObToDatum *arg, PyObject *string, bool inarray)
    1295                 : {
    1296                 :     char       *str;
    1297                 : 
    1298                 :     /*
    1299                 :      * Set up call data for record_in, if we didn't already.  (We can't just
    1300                 :      * use DirectFunctionCall, because record_in needs a fn_extra field.)
    1301                 :      */
    1302              18 :     if (!OidIsValid(arg->u.tuple.recinfunc.fn_oid))
    1303               5 :         fmgr_info_cxt(F_RECORD_IN, &arg->u.tuple.recinfunc, arg->mcxt);
    1304                 : 
    1305              18 :     str = PLyObject_AsString(string);
    1306                 : 
    1307                 :     /*
    1308                 :      * If we are parsing a composite type within an array, and the string
    1309                 :      * isn't a valid record literal, there's a high chance that the function
    1310                 :      * did something like:
    1311                 :      *
    1312                 :      * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
    1313                 :      * LANGUAGE plpython;
    1314                 :      *
    1315                 :      * Before PostgreSQL 10, that was interpreted as a single-dimensional
    1316                 :      * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
    1317                 :      * for multi-dimensional arrays, and it is now interpreted as a
    1318                 :      * two-dimensional array, containing two records, 'foo', and 'bar'.
    1319                 :      * record_in() will throw an error, because "foo" is not a valid record
    1320                 :      * literal.
    1321                 :      *
    1322                 :      * To make that less confusing to users who are upgrading from older
    1323                 :      * versions, try to give a hint in the typical instances of that. If we
    1324                 :      * are parsing an array of composite types, and we see a string literal
    1325                 :      * that is not a valid record literal, give a hint. We only want to give
    1326                 :      * the hint in the narrow case of a malformed string literal, not any
    1327                 :      * error from record_in(), so check for that case here specifically.
    1328                 :      *
    1329                 :      * This check better match the one in record_in(), so that we don't forbid
    1330                 :      * literals that are actually valid!
    1331                 :      */
    1332              18 :     if (inarray)
    1333                 :     {
    1334               1 :         char       *ptr = str;
    1335                 : 
    1336                 :         /* Allow leading whitespace */
    1337               1 :         while (*ptr && isspace((unsigned char) *ptr))
    1338 UBC           0 :             ptr++;
    1339 CBC           1 :         if (*ptr++ != '(')
    1340               1 :             ereport(ERROR,
    1341                 :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1342                 :                      errmsg("malformed record literal: \"%s\"", str),
    1343                 :                      errdetail("Missing left parenthesis."),
    1344                 :                      errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".")));
    1345                 :     }
    1346                 : 
    1347              17 :     return InputFunctionCall(&arg->u.tuple.recinfunc,
    1348                 :                              str,
    1349                 :                              arg->typoid,
    1350                 :                              arg->typmod);
    1351                 : }
    1352                 : 
    1353                 : 
    1354                 : static Datum
    1355              93 : PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
    1356                 : {
    1357                 :     Datum       result;
    1358                 :     HeapTuple   tuple;
    1359                 :     Datum      *values;
    1360                 :     bool       *nulls;
    1361                 :     volatile int i;
    1362                 : 
    1363              93 :     Assert(PyMapping_Check(mapping));
    1364                 : 
    1365                 :     /* Build tuple */
    1366              93 :     values = palloc(sizeof(Datum) * desc->natts);
    1367              93 :     nulls = palloc(sizeof(bool) * desc->natts);
    1368             361 :     for (i = 0; i < desc->natts; ++i)
    1369                 :     {
    1370                 :         char       *key;
    1371                 :         PyObject   *volatile value;
    1372                 :         PLyObToDatum *att;
    1373             271 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
    1374                 : 
    1375             271 :         if (attr->attisdropped)
    1376                 :         {
    1377              47 :             values[i] = (Datum) 0;
    1378              47 :             nulls[i] = true;
    1379              47 :             continue;
    1380                 :         }
    1381                 : 
    1382             224 :         key = NameStr(attr->attname);
    1383             224 :         value = NULL;
    1384             224 :         att = &arg->u.tuple.atts[i];
    1385             224 :         PG_TRY();
    1386                 :         {
    1387             224 :             value = PyMapping_GetItemString(mapping, key);
    1388             224 :             if (!value)
    1389               2 :                 ereport(ERROR,
    1390                 :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1391                 :                          errmsg("key \"%s\" not found in mapping", key),
    1392                 :                          errhint("To return null in a column, "
    1393                 :                                  "add the value None to the mapping with the key named after the column.")));
    1394                 : 
    1395             222 :             values[i] = att->func(att, value, &nulls[i], false);
    1396                 : 
    1397             221 :             Py_XDECREF(value);
    1398             221 :             value = NULL;
    1399                 :         }
    1400               3 :         PG_CATCH();
    1401                 :         {
    1402               3 :             Py_XDECREF(value);
    1403               3 :             PG_RE_THROW();
    1404                 :         }
    1405             221 :         PG_END_TRY();
    1406                 :     }
    1407                 : 
    1408              90 :     tuple = heap_form_tuple(desc, values, nulls);
    1409              90 :     result = heap_copy_tuple_as_datum(tuple, desc);
    1410              90 :     heap_freetuple(tuple);
    1411                 : 
    1412              90 :     pfree(values);
    1413              90 :     pfree(nulls);
    1414                 : 
    1415              90 :     return result;
    1416                 : }
    1417                 : 
    1418                 : 
    1419                 : static Datum
    1420             132 : PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
    1421                 : {
    1422                 :     Datum       result;
    1423                 :     HeapTuple   tuple;
    1424                 :     Datum      *values;
    1425                 :     bool       *nulls;
    1426                 :     volatile int idx;
    1427                 :     volatile int i;
    1428                 : 
    1429             132 :     Assert(PySequence_Check(sequence));
    1430                 : 
    1431                 :     /*
    1432                 :      * Check that sequence length is exactly same as PG tuple's. We actually
    1433                 :      * can ignore exceeding items or assume missing ones as null but to avoid
    1434                 :      * plpython developer's errors we are strict here
    1435                 :      */
    1436             132 :     idx = 0;
    1437             443 :     for (i = 0; i < desc->natts; i++)
    1438                 :     {
    1439             311 :         if (!TupleDescAttr(desc, i)->attisdropped)
    1440             260 :             idx++;
    1441                 :     }
    1442             132 :     if (PySequence_Length(sequence) != idx)
    1443               3 :         ereport(ERROR,
    1444                 :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1445                 :                  errmsg("length of returned sequence did not match number of columns in row")));
    1446                 : 
    1447                 :     /* Build tuple */
    1448             129 :     values = palloc(sizeof(Datum) * desc->natts);
    1449             129 :     nulls = palloc(sizeof(bool) * desc->natts);
    1450             129 :     idx = 0;
    1451             430 :     for (i = 0; i < desc->natts; ++i)
    1452                 :     {
    1453                 :         PyObject   *volatile value;
    1454                 :         PLyObToDatum *att;
    1455                 : 
    1456             303 :         if (TupleDescAttr(desc, i)->attisdropped)
    1457                 :         {
    1458              47 :             values[i] = (Datum) 0;
    1459              47 :             nulls[i] = true;
    1460              47 :             continue;
    1461                 :         }
    1462                 : 
    1463             256 :         value = NULL;
    1464             256 :         att = &arg->u.tuple.atts[i];
    1465             256 :         PG_TRY();
    1466                 :         {
    1467             256 :             value = PySequence_GetItem(sequence, idx);
    1468             256 :             Assert(value);
    1469                 : 
    1470             256 :             values[i] = att->func(att, value, &nulls[i], false);
    1471                 : 
    1472             254 :             Py_XDECREF(value);
    1473             254 :             value = NULL;
    1474                 :         }
    1475               2 :         PG_CATCH();
    1476                 :         {
    1477               2 :             Py_XDECREF(value);
    1478               2 :             PG_RE_THROW();
    1479                 :         }
    1480             254 :         PG_END_TRY();
    1481                 : 
    1482             254 :         idx++;
    1483                 :     }
    1484                 : 
    1485             127 :     tuple = heap_form_tuple(desc, values, nulls);
    1486             127 :     result = heap_copy_tuple_as_datum(tuple, desc);
    1487             127 :     heap_freetuple(tuple);
    1488                 : 
    1489             127 :     pfree(values);
    1490             127 :     pfree(nulls);
    1491                 : 
    1492             127 :     return result;
    1493                 : }
    1494                 : 
    1495                 : 
    1496                 : static Datum
    1497              25 : PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object, bool inarray)
    1498                 : {
    1499                 :     Datum       result;
    1500                 :     HeapTuple   tuple;
    1501                 :     Datum      *values;
    1502                 :     bool       *nulls;
    1503                 :     volatile int i;
    1504                 : 
    1505                 :     /* Build tuple */
    1506              25 :     values = palloc(sizeof(Datum) * desc->natts);
    1507              25 :     nulls = palloc(sizeof(bool) * desc->natts);
    1508              98 :     for (i = 0; i < desc->natts; ++i)
    1509                 :     {
    1510                 :         char       *key;
    1511                 :         PyObject   *volatile value;
    1512                 :         PLyObToDatum *att;
    1513              74 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
    1514                 : 
    1515              74 :         if (attr->attisdropped)
    1516                 :         {
    1517              24 :             values[i] = (Datum) 0;
    1518              24 :             nulls[i] = true;
    1519              24 :             continue;
    1520                 :         }
    1521                 : 
    1522              50 :         key = NameStr(attr->attname);
    1523              50 :         value = NULL;
    1524              50 :         att = &arg->u.tuple.atts[i];
    1525              50 :         PG_TRY();
    1526                 :         {
    1527              50 :             value = PyObject_GetAttrString(object, key);
    1528              50 :             if (!value)
    1529                 :             {
    1530                 :                 /*
    1531                 :                  * No attribute for this column in the object.
    1532                 :                  *
    1533                 :                  * If we are parsing a composite type in an array, a likely
    1534                 :                  * cause is that the function contained something like "[[123,
    1535                 :                  * 'foo']]". Before PostgreSQL 10, that was interpreted as an
    1536                 :                  * array, with a composite type (123, 'foo') in it. But now
    1537                 :                  * it's interpreted as a two-dimensional array, and we try to
    1538                 :                  * interpret "123" as the composite type. See also similar
    1539                 :                  * heuristic in PLyObject_ToScalar().
    1540                 :                  */
    1541               1 :                 ereport(ERROR,
    1542                 :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1543                 :                          errmsg("attribute \"%s\" does not exist in Python object", key),
    1544                 :                          inarray ?
    1545                 :                          errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g., \"[('foo',)]\".") :
    1546                 :                          errhint("To return null in a column, let the returned object have an attribute named after column with value None.")));
    1547                 :             }
    1548                 : 
    1549              49 :             values[i] = att->func(att, value, &nulls[i], false);
    1550                 : 
    1551              49 :             Py_XDECREF(value);
    1552              49 :             value = NULL;
    1553                 :         }
    1554               1 :         PG_CATCH();
    1555                 :         {
    1556               1 :             Py_XDECREF(value);
    1557               1 :             PG_RE_THROW();
    1558                 :         }
    1559              49 :         PG_END_TRY();
    1560                 :     }
    1561                 : 
    1562              24 :     tuple = heap_form_tuple(desc, values, nulls);
    1563              24 :     result = heap_copy_tuple_as_datum(tuple, desc);
    1564              24 :     heap_freetuple(tuple);
    1565                 : 
    1566              24 :     pfree(values);
    1567              24 :     pfree(nulls);
    1568                 : 
    1569              24 :     return result;
    1570                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a