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 17:13:01 Functions: 100.0 % 36 36 36
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 96.8 % 570 552 18 552
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 36 36 36

 Age         Owner                  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 *
 1970 tgl                        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 *
 1471 peter                     133             194 : PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
                                134                 : {
                                135                 :     PyObject   *dict;
 2905 peter_e                   136             194 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
 1970 tgl                       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                 : 
 1471 peter                     147             194 :     dict = PLyDict_FromTuple(arg, tuple, desc, include_generated);
                                148                 : 
 1970 tgl                       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 */
 4130 peter_e                   187             589 :     for (i = 0; i < desc->natts; i++)
                                188                 :     {
 2058 andres                    189             404 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
 1970 tgl                       190             404 :         PLyDatumToOb *att = &arg->u.tuple.atts[i];
                                191                 : 
 2058 andres                    192             404 :         if (attr->attisdropped)
 4130 peter_e                   193               3 :             continue;
                                194                 : 
 1970 tgl                       195             401 :         if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
 4130 peter_e                   196             223 :             continue;           /* already set up this entry */
                                197                 : 
 1970 tgl                       198             178 :         PLy_input_setup_func(att, arg->mcxt,
                                199                 :                              attr->atttypid, attr->atttypmod,
                                200                 :                              proc);
                                201                 :     }
 4130 peter_e                   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
 1970 tgl                       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)
 1970 tgl                       223 UBC           0 :         arg->u.tuple.recdesc = desc;
                                224                 : 
                                225                 :     /* (Re)allocate atts array as needed */
 1970 tgl                       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 */
 4130 peter_e                   237             492 :     for (i = 0; i < desc->natts; i++)
                                238                 :     {
 2058 andres                    239             341 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
 1970 tgl                       240             341 :         PLyObToDatum *att = &arg->u.tuple.atts[i];
                                241                 : 
 2058 andres                    242             341 :         if (attr->attisdropped)
 4130 peter_e                   243              28 :             continue;
                                244                 : 
 1970 tgl                       245             313 :         if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod)
 4130 peter_e                   246             160 :             continue;           /* already set up this entry */
                                247                 : 
 1970 tgl                       248             153 :         PLy_output_setup_func(att, arg->mcxt,
                                249                 :                               attr->atttypid, attr->atttypmod,
                                250                 :                               proc);
                                251                 :     }
 4130 peter_e                   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
 1970 tgl                       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                 :      */
 4130 peter_e                   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                 :      */
 1970 tgl                       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);
 4130 peter_e                   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
 1970 tgl                       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;
 1131                           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                 :      */
 1970                           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 &&
  851                           355             421 :              IsTrueArrayType(typentry))
                                356                 :     {
                                357                 :         /* Standard array */
 1970                           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                 :     {
 2905 peter_e                   373              11 :         arg->func = PLyObject_ToTransform;
 1970 tgl                       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 */
 2905 peter_e                   379              71 :         arg->func = PLyObject_ToComposite;
                                380                 :         /* We'll set up the per-field data later */
 1970 tgl                       381              71 :         arg->u.tuple.recdesc = NULL;
                                382              71 :         arg->u.tuple.typentry = typentry;
 1881                           383              71 :         arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
 1970                           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                 :         {
 2878 bruce                     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:
 1970 tgl                       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);
 2878 bruce                     404             305 :                 break;
                                405                 :         }
                                406                 :     }
 4130 peter_e                   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
 1970 tgl                       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;
 1131                           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                 :      */
 1970                           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 &&
  851                           473             371 :              IsTrueArrayType(typentry))
                                474                 :     {
                                475                 :         /* Standard array */
 1970                           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                 :     {
 2905 peter_e                   488              16 :         arg->func = PLyObject_FromTransform;
 1970 tgl                       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;
 1881                           498             116 :         arg->u.tuple.tupdescid = INVALID_TUPLEDESC_IDENTIFIER;
 1970                           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                 :         {
 2878 bruce                     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:
  398 andres                    520               4 :                 arg->func = PLyLong_FromInt16;
 2878 bruce                     521               4 :                 break;
                                522             141 :             case INT4OID:
  398 andres                    523             141 :                 arg->func = PLyLong_FromInt32;
 2878 bruce                     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:
  398 andres                    535             127 :                 arg->func = PLyUnicode_FromScalar;
 1970 tgl                       536             127 :                 getTypeOutputInfo(typeOid, &typoutput, &typisvarlena);
                                537             127 :                 fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt);
 2878 bruce                     538             127 :                 break;
                                539                 :         }
                                540                 :     }
 4130 peter_e                   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))
 2238                           552              26 :         Py_RETURN_TRUE;
                                553              95 :     Py_RETURN_FALSE;
                                554                 : }
                                555                 : 
                                556                 : static PyObject *
 4130                           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 *
 3565                           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)
 3565 peter_e                   587 UBC           0 :             PLy_elog(ERROR, "could not import a module for Decimal constructor");
                                588                 : 
 3565 peter_e                   589 CBC           1 :         decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
                                590               1 :         if (!decimal_constructor)
 3565 peter_e                   591 UBC           0 :             PLy_elog(ERROR, "no Decimal attribute in module");
                                592                 :     }
                                593                 : 
 3565 peter_e                   594 CBC           7 :     str = DatumGetCString(DirectFunctionCall1(numeric_out, d));
                                595               7 :     pyvalue = PyObject_CallFunction(decimal_constructor, "s", str);
                                596               7 :     if (!pyvalue)
 3565 peter_e                   597 UBC           0 :         PLy_elog(ERROR, "conversion from numeric to Decimal failed");
                                598                 : 
 3565 peter_e                   599 CBC           7 :     return pyvalue;
                                600                 : }
                                601                 : 
                                602                 : static PyObject *
  398 andres                    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 *
 4130 peter_e                   615              15 : PLyLong_FromInt64(PLyDatumToOb *arg, Datum d)
                                616                 : {
 1906                           617              15 :     return PyLong_FromLongLong(DatumGetInt64(d));
                                618                 : }
                                619                 : 
                                620                 : static PyObject *
 3844                           621               2 : PLyLong_FromOid(PLyDatumToOb *arg, Datum d)
                                622                 : {
                                623               2 :     return PyLong_FromUnsignedLong(DatumGetObjectId(d));
                                624                 : }
                                625                 : 
                                626                 : static PyObject *
 4130                           627              11 : PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d)
                                628                 : {
 2219 noah                      629              11 :     text       *txt = DatumGetByteaPP(d);
                                630              11 :     char       *str = VARDATA_ANY(txt);
                                631              11 :     size_t      size = VARSIZE_ANY_EXHDR(txt);
                                632                 : 
 4130 peter_e                   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 *
  398 andres                    641             482 : PLyUnicode_FromScalar(PLyDatumToOb *arg, Datum d)
                                642                 : {
 1970 tgl                       643             482 :     char       *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
  398 andres                    644             482 :     PyObject   *r = PLyUnicode_FromString(x);
                                645                 : 
 4130 peter_e                   646             482 :     pfree(x);
                                647             482 :     return r;
                                648                 : }
                                649                 : 
                                650                 : /*
                                651                 :  * Convert using a from-SQL transform function.
                                652                 :  */
                                653                 : static PyObject *
 2905                           654              35 : PLyObject_FromTransform(PLyDatumToOb *arg, Datum d)
                                655                 : {
                                656                 :     Datum       t;
                                657                 : 
 1970 tgl                       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 *
 4130 peter_e                   666              21 : PLyList_FromArray(PLyDatumToOb *arg, Datum d)
                                667                 : {
                                668              21 :     ArrayType  *array = DatumGetArrayTypeP(d);
 1970 tgl                       669              21 :     PLyDatumToOb *elm = arg->u.array.elm;
                                670                 :     int         ndim;
                                671                 :     int        *dims;
                                672                 :     char       *dataptr;
                                673                 :     bits8      *bitmap;
                                674                 :     int         bitmask;
                                675                 : 
 4130 peter_e                   676              21 :     if (ARR_NDIM(array) == 0)
                                677               1 :         return PyList_New(0);
                                678                 : 
                                679                 :     /* Array dimensions and left bounds */
 2356 heikki.linnakangas        680              20 :     ndim = ARR_NDIM(array);
                                681              20 :     dims = ARR_DIMS(array);
  920                           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                 :      */
 2356                           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]);
 1986 peter_e                   713              48 :     if (!list)
 1986 peter_e                   714 UBC           0 :         return NULL;
                                715                 : 
 2356 heikki.linnakangas        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                 : 
 4130 peter_e                   773              48 :     return list;
                                774                 : }
                                775                 : 
                                776                 : /*
                                777                 :  * Convert a composite SQL value to a Python dict.
                                778                 :  */
                                779                 : static PyObject *
 1970 tgl                       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                 : 
 1471 peter                     803              49 :     dict = PLyDict_FromTuple(arg, &tmptup, tupdesc, true);
                                804                 : 
 1970 tgl                       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 *
 1471 peter                     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 */
 1970 tgl                       819             243 :     Assert(desc->natts == arg->u.tuple.natts);
                                820                 : 
                                821             243 :     dict = PyDict_New();
                                822             243 :     if (dict == NULL)
 1986 peter_e                   823 UBC           0 :         return NULL;
                                824                 : 
 1970 tgl                       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                 : 
 1471 peter                     841             512 :             if (attr->attgenerated)
                                842                 :             {
                                843                 :                 /* don't include unless requested */
                                844               9 :                 if (!include_generated)
                                845               3 :                     continue;
                                846                 :             }
                                847                 : 
 1970 tgl                       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                 :     }
 1970 tgl                       861 UBC           0 :     PG_CATCH();
                                862                 :     {
                                863               0 :         Py_DECREF(dict);
                                864               0 :         PG_RE_THROW();
                                865                 :     }
 1970 tgl                       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                 : {
 4130 peter_e                   899              11 :     PyObject   *volatile plrv_so = NULL;
 1252 peter                     900              11 :     Datum       rv = (Datum) 0;
                                901                 : 
 1970 tgl                       902              11 :     if (plrv == Py_None)
                                903                 :     {
                                904               3 :         *isnull = true;
                                905               3 :         return (Datum) 0;
                                906                 :     }
                                907               8 :     *isnull = false;
                                908                 : 
 4130 peter_e                   909               8 :     plrv_so = PyObject_Bytes(plrv);
                                910               8 :     if (!plrv_so)
 4130 peter_e                   911 UBC           0 :         PLy_elog(ERROR, "could not create bytes representation of Python object");
                                912                 : 
 4130 peter_e                   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                 :     }
 1255 peter                     924 UBC           0 :     PG_FINALLY();
                                925                 :     {
 4130 peter_e                   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
 1970 tgl                       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                 :      */
  398 andres                    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                 :      */
 1970 tgl                       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 */
 1881                           972             125 :         if (arg->u.tuple.tupdescid != arg->u.tuple.typentry->tupDesc_identifier)
                                973                 :         {
 1970                           974              31 :             PLy_output_setup_tuple(arg, desc,
                                975              31 :                                    PLy_current_execution_context()->curr_proc);
 1881                           976              31 :             arg->u.tuple.tupdescid = arg->u.tuple.typentry->tupDesc_identifier;
                                977                 :         }
                                978                 :     }
                                979                 :     else
                                980                 :     {
 1970                           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                 : 
 3202                          1011             241 :     ReleaseTupleDesc(desc);
                               1012                 : 
 4130 peter_e                  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 *
 2905                          1023            1570 : PLyObject_AsString(PyObject *plrv)
                               1024                 : {
                               1025                 :     PyObject   *plrv_bo;
                               1026                 :     char       *plrv_sc;
                               1027                 :     size_t      plen;
                               1028                 :     size_t      slen;
                               1029                 : 
 4130                          1030            1570 :     if (PyUnicode_Check(plrv))
                               1031             333 :         plrv_bo = PLyUnicode_Bytes(plrv);
 2951                          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                 :     {
 4130                          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)
 4130 peter_e                  1048 UBC           0 :         PLy_elog(ERROR, "could not create string representation of Python object");
                               1049                 : 
 2905 peter_e                  1050 CBC        1570 :     plrv_sc = pstrdup(PyBytes_AsString(plrv_bo));
                               1051            1570 :     plen = PyBytes_Size(plrv_bo);
                               1052            1570 :     slen = strlen(plrv_sc);
                               1053                 : 
 4130                          1054            1570 :     Py_XDECREF(plrv_bo);
                               1055                 : 
 2905                          1056            1570 :     if (slen < plen)
 2905 peter_e                  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")));
 2905 peter_e                  1060 CBC        1570 :     else if (slen > plen)
 2905 peter_e                  1061 UBC           0 :         elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
 2905 peter_e                  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
 1970 tgl                      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                 : 
 2356 heikki.linnakangas       1085            1491 :     str = PLyObject_AsString(plrv);
                               1086                 : 
 1970 tgl                      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;
 2356 heikki.linnakangas       1144              50 :     PyObject   *pyptr = plrv;
                               1145                 :     PyObject   *next;
                               1146                 : 
 1970 tgl                      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                 :      */
 2356 heikki.linnakangas       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)
  919                          1168               1 :             ereport(ERROR,
                               1169                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               1170                 :                      errmsg("number of array dimensions exceeds the maximum allowed (%d)",
                               1171                 :                             MAXDIM)));
                               1172                 : 
 2356                          1173              75 :         dims[ndim] = PySequence_Length(pyptr);
                               1174              75 :         if (dims[ndim] < 0)
 2074 peter_e                  1175 UBC           0 :             PLy_elog(ERROR, "could not determine sequence length for function return value");
                               1176                 : 
 2356 heikki.linnakangas       1177 CBC          75 :         if (dims[ndim] > MaxAllocSize)
  919 heikki.linnakangas       1178 UBC           0 :             ereport(ERROR,
                               1179                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               1180                 :                      errmsg("array size exceeds the maximum allowed")));
                               1181                 : 
 2356 heikki.linnakangas       1182 CBC          75 :         len *= dims[ndim];
                               1183              75 :         if (len > MaxAllocSize)
  919 heikki.linnakangas       1184 UBC           0 :             ereport(ERROR,
                               1185                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               1186                 :                      errmsg("array size exceeds the maximum allowed")));
                               1187                 : 
 2356 heikki.linnakangas       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))
  919                          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                 : 
 2356                          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;
 1970 tgl                      1227              44 :     PLySequence_ToArray_recurse(arg->u.array.elm, plrv,
                               1228                 :                                 dims, ndim, 0,
                               1229                 :                                 elems, nulls, &currelem);
                               1230                 : 
 2356 heikki.linnakangas       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,
 1970 tgl                      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
 2356 heikki.linnakangas       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])
 2074 peter_e                  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                 : 
 2356 heikki.linnakangas       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                 : 
 1970 tgl                      1282             907 :             elems[*currelem] = elm->func(elm, obj, &nulls[*currelem], true);
 2356 heikki.linnakangas       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
  398 andres                   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                 :      */
 1970 tgl                      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))
 1970 tgl                      1338 UBC           0 :             ptr++;
 1970 tgl                      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                 : 
 4130 peter_e                  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;
 2058 andres                   1373             271 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
                               1374                 : 
                               1375             271 :         if (attr->attisdropped)
                               1376                 :         {
 4130 peter_e                  1377              47 :             values[i] = (Datum) 0;
                               1378              47 :             nulls[i] = true;
                               1379              47 :             continue;
                               1380                 :         }
                               1381                 : 
 2058 andres                   1382             224 :         key = NameStr(attr->attname);
 4130 peter_e                  1383             224 :         value = NULL;
 1970 tgl                      1384             224 :         att = &arg->u.tuple.atts[i];
 4130 peter_e                  1385             224 :         PG_TRY();
                               1386                 :         {
                               1387             224 :             value = PyMapping_GetItemString(mapping, key);
 1970 tgl                      1388             224 :             if (!value)
 4130 peter_e                  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                 : 
 1970 tgl                      1395             222 :             values[i] = att->func(att, value, &nulls[i], false);
                               1396                 : 
 4130 peter_e                  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);
 3202 tgl                      1409              90 :     result = heap_copy_tuple_as_datum(tuple, desc);
                               1410              90 :     heap_freetuple(tuple);
                               1411                 : 
 4130 peter_e                  1412              90 :     pfree(values);
                               1413              90 :     pfree(nulls);
                               1414                 : 
 3202 tgl                      1415              90 :     return result;
                               1416                 : }
                               1417                 : 
                               1418                 : 
                               1419                 : static Datum
 1970                          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                 : 
 4130 peter_e                  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                 :     {
 2058 andres                   1439             311 :         if (!TupleDescAttr(desc, i)->attisdropped)
 4130 peter_e                  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                 : 
 2058 andres                   1456             303 :         if (TupleDescAttr(desc, i)->attisdropped)
                               1457                 :         {
 4130 peter_e                  1458              47 :             values[i] = (Datum) 0;
                               1459              47 :             nulls[i] = true;
                               1460              47 :             continue;
                               1461                 :         }
                               1462                 : 
                               1463             256 :         value = NULL;
 1970 tgl                      1464             256 :         att = &arg->u.tuple.atts[i];
 4130 peter_e                  1465             256 :         PG_TRY();
                               1466                 :         {
                               1467             256 :             value = PySequence_GetItem(sequence, idx);
                               1468             256 :             Assert(value);
                               1469                 : 
 1970 tgl                      1470             256 :             values[i] = att->func(att, value, &nulls[i], false);
                               1471                 : 
 4130 peter_e                  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);
 3202 tgl                      1486             127 :     result = heap_copy_tuple_as_datum(tuple, desc);
                               1487             127 :     heap_freetuple(tuple);
                               1488                 : 
 4130 peter_e                  1489             127 :     pfree(values);
                               1490             127 :     pfree(nulls);
                               1491                 : 
 3202 tgl                      1492             127 :     return result;
                               1493                 : }
                               1494                 : 
                               1495                 : 
                               1496                 : static Datum
 1970                          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 */
 4130 peter_e                  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;
 2058 andres                   1513              74 :         Form_pg_attribute attr = TupleDescAttr(desc, i);
                               1514                 : 
                               1515              74 :         if (attr->attisdropped)
                               1516                 :         {
 4130 peter_e                  1517              24 :             values[i] = (Datum) 0;
                               1518              24 :             nulls[i] = true;
                               1519              24 :             continue;
                               1520                 :         }
                               1521                 : 
 2058 andres                   1522              50 :         key = NameStr(attr->attname);
 4130 peter_e                  1523              50 :         value = NULL;
 1970 tgl                      1524              50 :         att = &arg->u.tuple.atts[i];
 4130 peter_e                  1525              50 :         PG_TRY();
                               1526                 :         {
                               1527              50 :             value = PyObject_GetAttrString(object, key);
 1970 tgl                      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                 :                  */
 4130 peter_e                  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                 : 
 1970 tgl                      1549              49 :             values[i] = att->func(att, value, &nulls[i], false);
                               1550                 : 
 4130 peter_e                  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);
 3202 tgl                      1563              24 :     result = heap_copy_tuple_as_datum(tuple, desc);
                               1564              24 :     heap_freetuple(tuple);
                               1565                 : 
 4130 peter_e                  1566              24 :     pfree(values);
                               1567              24 :     pfree(nulls);
                               1568                 : 
 3202 tgl                      1569              24 :     return result;
                               1570                 : }
        

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