Header And Logo

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

Functions

plpy_typeio.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/transam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "parser/parse_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
#include "plpython.h"
#include "plpy_typeio.h"
#include "plpy_elog.h"
#include "plpy_main.h"
Include dependency graph for plpy_typeio.c:

Go to the source code of this file.

Functions

static void PLy_input_datum_func2 (PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup)
static void PLy_output_datum_func2 (PLyObToDatum *arg, HeapTuple typeTup)
static PyObject * PLyBool_FromBool (PLyDatumToOb *arg, Datum d)
static PyObject * PLyFloat_FromFloat4 (PLyDatumToOb *arg, Datum d)
static PyObject * PLyFloat_FromFloat8 (PLyDatumToOb *arg, Datum d)
static PyObject * PLyFloat_FromNumeric (PLyDatumToOb *arg, Datum d)
static PyObject * PLyInt_FromInt16 (PLyDatumToOb *arg, Datum d)
static PyObject * PLyInt_FromInt32 (PLyDatumToOb *arg, Datum d)
static PyObject * PLyLong_FromInt64 (PLyDatumToOb *arg, Datum d)
static PyObject * PLyLong_FromOid (PLyDatumToOb *arg, Datum d)
static PyObject * PLyBytes_FromBytea (PLyDatumToOb *arg, Datum d)
static PyObject * PLyString_FromDatum (PLyDatumToOb *arg, Datum d)
static PyObject * PLyList_FromArray (PLyDatumToOb *arg, Datum d)
static Datum PLyObject_ToBool (PLyObToDatum *arg, int32 typmod, PyObject *plrv)
static Datum PLyObject_ToBytea (PLyObToDatum *arg, int32 typmod, PyObject *plrv)
static Datum PLyObject_ToComposite (PLyObToDatum *arg, int32 typmod, PyObject *plrv)
static Datum PLyObject_ToDatum (PLyObToDatum *arg, int32 typmod, PyObject *plrv)
static Datum PLySequence_ToArray (PLyObToDatum *arg, int32 typmod, PyObject *plrv)
static Datum PLyString_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *string)
static Datum PLyMapping_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
static Datum PLySequence_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
static Datum PLyGenericObject_ToComposite (PLyTypeInfo *info, TupleDesc desc, PyObject *object)
static void perm_fmgr_info (Oid functionId, FmgrInfo *finfo)
void PLy_typeinfo_init (PLyTypeInfo *arg)
void PLy_typeinfo_dealloc (PLyTypeInfo *arg)
void PLy_input_datum_func (PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup)
void PLy_output_datum_func (PLyTypeInfo *arg, HeapTuple typeTup)
void PLy_input_tuple_funcs (PLyTypeInfo *arg, TupleDesc desc)
void PLy_output_tuple_funcs (PLyTypeInfo *arg, TupleDesc desc)
void PLy_output_record_funcs (PLyTypeInfo *arg, TupleDesc desc)
PyObject * PLyDict_FromTuple (PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
Datum PLyObject_ToCompositeDatum (PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)

Function Documentation

static void perm_fmgr_info ( Oid  functionId,
FmgrInfo finfo 
) [static]

Definition at line 1090 of file plpy_typeio.c.

References fmgr_info_cxt(), and TopMemoryContext.

Referenced by PLy_input_datum_func2(), and PLy_output_datum_func2().

{
    fmgr_info_cxt(functionId, finfo, TopMemoryContext);
}

void PLy_input_datum_func ( PLyTypeInfo arg,
Oid  typeOid,
HeapTuple  typeTup 
)

Definition at line 104 of file plpy_typeio.c.

References PLyTypeInput::d, elog, ERROR, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, and PLy_input_datum_func2().

Referenced by PLy_procedure_create().

{
    if (arg->is_rowtype > 0)
        elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
    arg->is_rowtype = 0;
    PLy_input_datum_func2(&(arg->in.d), typeOid, typeTup);
}

static void PLy_input_datum_func2 ( PLyDatumToOb arg,
Oid  typeOid,
HeapTuple  typeTup 
) [static]

Definition at line 426 of file plpy_typeio.c.

References BOOLOID, BYTEAOID, PLyDatumToOb::elm, FLOAT4OID, FLOAT8OID, PLyDatumToOb::func, get_element_type(), get_type_io_data(), getBaseType(), GETSTRUCT, getTypeIOParam(), HeapTupleGetOid, INT2OID, INT4OID, INT8OID, IOFunc_output, NUMERICOID, OIDOID, perm_fmgr_info(), PLy_malloc0(), PLyDatumToOb::typalign, PLyDatumToOb::typbyval, PLyDatumToOb::typfunc, PLyDatumToOb::typioparam, PLyDatumToOb::typlen, PLyDatumToOb::typmod, and PLyDatumToOb::typoid.

Referenced by PLy_input_datum_func(), and PLy_input_tuple_funcs().

{
    Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    Oid         element_type = get_element_type(typeOid);

    /* Get the type's conversion information */
    perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
    arg->typoid = HeapTupleGetOid(typeTup);
    arg->typmod = -1;
    arg->typioparam = getTypeIOParam(typeTup);
    arg->typbyval = typeStruct->typbyval;
    arg->typlen = typeStruct->typlen;
    arg->typalign = typeStruct->typalign;

    /* Determine which kind of Python object we will convert to */
    switch (getBaseType(element_type ? element_type : typeOid))
    {
        case BOOLOID:
            arg->func = PLyBool_FromBool;
            break;
        case FLOAT4OID:
            arg->func = PLyFloat_FromFloat4;
            break;
        case FLOAT8OID:
            arg->func = PLyFloat_FromFloat8;
            break;
        case NUMERICOID:
            arg->func = PLyFloat_FromNumeric;
            break;
        case INT2OID:
            arg->func = PLyInt_FromInt16;
            break;
        case INT4OID:
            arg->func = PLyInt_FromInt32;
            break;
        case INT8OID:
            arg->func = PLyLong_FromInt64;
            break;
        case OIDOID:
            arg->func = PLyLong_FromOid;
            break;
        case BYTEAOID:
            arg->func = PLyBytes_FromBytea;
            break;
        default:
            arg->func = PLyString_FromDatum;
            break;
    }

    if (element_type)
    {
        char        dummy_delim;
        Oid         funcid;

        arg->elm = PLy_malloc0(sizeof(*arg->elm));
        arg->elm->func = arg->func;
        arg->func = PLyList_FromArray;
        arg->elm->typoid = element_type;
        arg->elm->typmod = -1;
        get_type_io_data(element_type, IOFunc_output,
                         &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
                         &arg->elm->typioparam, &funcid);
        perm_fmgr_info(funcid, &arg->elm->typfunc);
    }
}

void PLy_input_tuple_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 122 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyTupleToOb::atts, elog, ERROR, HeapTupleHeaderGetXmin, HeapTupleIsValid, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, tupleDesc::natts, PLyTupleToOb::natts, ObjectIdGetDatum, OidIsValid, PLy_free(), PLy_input_datum_func2(), PLy_malloc0(), PLyTypeInput::r, RECORDOID, ReleaseSysCache(), RELOID, SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, tupleDesc::tdtypeid, tupleDesc::tdtypmod, PLyTypeInfo::typ_relid, typeidTypeRelid(), TYPEOID, PLyDatumToOb::typoid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_exec_trigger(), PLy_function_build_args(), and PLy_spi_execute_fetch_result().

{
    int         i;

    if (arg->is_rowtype == 0)
        elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
    arg->is_rowtype = 1;

    if (arg->in.r.natts != desc->natts)
    {
        if (arg->in.r.atts)
            PLy_free(arg->in.r.atts);
        arg->in.r.natts = desc->natts;
        arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
    }

    /* Can this be an unnamed tuple? If not, then an Assert would be enough */
    if (desc->tdtypmod != -1)
        elog(ERROR, "received unnamed record type as input");

    Assert(OidIsValid(desc->tdtypeid));

    /*
     * RECORDOID means we got called to create input functions for a tuple
     * fetched by plpy.execute or for an anonymous record type
     */
    if (desc->tdtypeid != RECORDOID)
    {
        HeapTuple   relTup;

        /* Get the pg_class tuple corresponding to the type of the input */
        arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
        relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
        if (!HeapTupleIsValid(relTup))
            elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);

        /* Remember XMIN and TID for later validation if cache is still OK */
        arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
        arg->typrel_tid = relTup->t_self;

        ReleaseSysCache(relTup);
    }

    for (i = 0; i < desc->natts; i++)
    {
        HeapTuple   typeTup;

        if (desc->attrs[i]->attisdropped)
            continue;

        if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
            continue;           /* already set up this entry */

        typeTup = SearchSysCache1(TYPEOID,
                                  ObjectIdGetDatum(desc->attrs[i]->atttypid));
        if (!HeapTupleIsValid(typeTup))
            elog(ERROR, "cache lookup failed for type %u",
                 desc->attrs[i]->atttypid);

        PLy_input_datum_func2(&(arg->in.r.atts[i]),
                              desc->attrs[i]->atttypid,
                              typeTup);

        ReleaseSysCache(typeTup);
    }
}

void PLy_output_datum_func ( PLyTypeInfo arg,
HeapTuple  typeTup 
)

Definition at line 113 of file plpy_typeio.c.

References PLyTypeOutput::d, elog, ERROR, PLyTypeInfo::is_rowtype, PLyTypeInfo::out, and PLy_output_datum_func2().

Referenced by PLy_procedure_create(), and PLy_spi_prepare().

{
    if (arg->is_rowtype > 0)
        elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
    arg->is_rowtype = 0;
    PLy_output_datum_func2(&(arg->out.d), typeTup);
}

static void PLy_output_datum_func2 ( PLyObToDatum arg,
HeapTuple  typeTup 
) [static]

Definition at line 364 of file plpy_typeio.c.

References BOOLOID, BYTEAOID, PLyObToDatum::elm, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), PLyObToDatum::func, get_element_type(), get_type_io_data(), getBaseType(), GETSTRUCT, getTypeIOParam(), HeapTupleGetOid, IOFunc_input, perm_fmgr_info(), PLy_malloc0(), PLyObToDatum::typalign, PLyObToDatum::typbyval, type_is_rowtype(), PLyObToDatum::typfunc, PLyObToDatum::typioparam, PLyObToDatum::typlen, PLyObToDatum::typmod, PLyObToDatum::typoid, and TYPTYPE_COMPOSITE.

Referenced by PLy_output_datum_func(), PLy_output_tuple_funcs(), and PLyString_ToComposite().

{
    Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    Oid         element_type;

    perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
    arg->typoid = HeapTupleGetOid(typeTup);
    arg->typmod = -1;
    arg->typioparam = getTypeIOParam(typeTup);
    arg->typbyval = typeStruct->typbyval;

    element_type = get_element_type(arg->typoid);

    /*
     * Select a conversion function to convert Python objects to PostgreSQL
     * datums.  Most data types can go through the generic function.
     */
    switch (getBaseType(element_type ? element_type : arg->typoid))
    {
        case BOOLOID:
            arg->func = PLyObject_ToBool;
            break;
        case BYTEAOID:
            arg->func = PLyObject_ToBytea;
            break;
        default:
            arg->func = PLyObject_ToDatum;
            break;
    }

    /* Composite types need their own input routine, though */
    if (typeStruct->typtype == TYPTYPE_COMPOSITE)
    {
        arg->func = PLyObject_ToComposite;
    }

    if (element_type)
    {
        char        dummy_delim;
        Oid         funcid;

        if (type_is_rowtype(element_type))
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("PL/Python functions cannot return type %s",
                            format_type_be(arg->typoid)),
                     errdetail("PL/Python does not support conversion to arrays of row types.")));

        arg->elm = PLy_malloc0(sizeof(*arg->elm));
        arg->elm->func = arg->func;
        arg->func = PLySequence_ToArray;

        arg->elm->typoid = element_type;
        arg->elm->typmod = -1;
        get_type_io_data(element_type, IOFunc_input,
                         &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
                         &arg->elm->typioparam, &funcid);
        perm_fmgr_info(funcid, &arg->elm->typfunc);
    }
}

void PLy_output_record_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 252 of file plpy_typeio.c.

References Assert, BlessTupleDesc(), PLyTypeOutput::d, PLyTypeInfo::is_rowtype, PLyTypeInfo::out, PLy_output_tuple_funcs(), tupleDesc::tdtypmod, and PLyObToDatum::typmod.

Referenced by PLy_function_build_args().

{
    /*
     * If the output record functions are already set, we just have to check
     * if the record descriptor has not changed
     */
    if ((arg->is_rowtype == 1) &&
        (arg->out.d.typmod != -1) &&
        (arg->out.d.typmod == desc->tdtypmod))
        return;

    /* bless the record to make it known to the typcache lookup code */
    BlessTupleDesc(desc);
    /* save the freshly generated typmod */
    arg->out.d.typmod = desc->tdtypmod;
    /* proceed with normal I/O function caching */
    PLy_output_tuple_funcs(arg, desc);

    /*
     * it should change is_rowtype to 1, so we won't go through this again
     * unless the output record description changes
     */
    Assert(arg->is_rowtype == 1);
}

void PLy_output_tuple_funcs ( PLyTypeInfo arg,
TupleDesc  desc 
)

Definition at line 190 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, elog, ERROR, HeapTupleHeaderGetXmin, HeapTupleIsValid, i, PLyTypeInfo::is_rowtype, tupleDesc::natts, PLyObToTuple::natts, ObjectIdGetDatum, OidIsValid, PLyTypeInfo::out, PLy_free(), PLy_malloc0(), PLy_output_datum_func2(), PLyTypeOutput::r, RECORDOID, ReleaseSysCache(), RELOID, SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, tupleDesc::tdtypeid, PLyTypeInfo::typ_relid, typeidTypeRelid(), TYPEOID, PLyObToDatum::typoid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.

Referenced by PLy_exec_trigger(), PLy_output_record_funcs(), PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), and PLySequence_ToComposite().

{
    int         i;

    if (arg->is_rowtype == 0)
        elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
    arg->is_rowtype = 1;

    if (arg->out.r.natts != desc->natts)
    {
        if (arg->out.r.atts)
            PLy_free(arg->out.r.atts);
        arg->out.r.natts = desc->natts;
        arg->out.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
    }

    Assert(OidIsValid(desc->tdtypeid));

    /*
     * RECORDOID means we got called to create output functions for an
     * anonymous record type
     */
    if (desc->tdtypeid != RECORDOID)
    {
        HeapTuple   relTup;

        /* Get the pg_class tuple corresponding to the type of the output */
        arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
        relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
        if (!HeapTupleIsValid(relTup))
            elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);

        /* Remember XMIN and TID for later validation if cache is still OK */
        arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
        arg->typrel_tid = relTup->t_self;

        ReleaseSysCache(relTup);
    }

    for (i = 0; i < desc->natts; i++)
    {
        HeapTuple   typeTup;

        if (desc->attrs[i]->attisdropped)
            continue;

        if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
            continue;           /* already set up this entry */

        typeTup = SearchSysCache1(TYPEOID,
                                  ObjectIdGetDatum(desc->attrs[i]->atttypid));
        if (!HeapTupleIsValid(typeTup))
            elog(ERROR, "cache lookup failed for type %u",
                 desc->attrs[i]->atttypid);

        PLy_output_datum_func2(&(arg->out.r.atts[i]), typeTup);

        ReleaseSysCache(typeTup);
    }
}

void PLy_typeinfo_dealloc ( PLyTypeInfo arg  ) 

Definition at line 76 of file plpy_typeio.c.

References PLyObToTuple::atts, PLyTupleToOb::atts, PLyObToDatum::elm, PLyDatumToOb::elm, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, PLyObToTuple::natts, PLyTupleToOb::natts, NULL, PLyTypeInfo::out, PLy_free(), PLyTypeOutput::r, and PLyTypeInput::r.

Referenced by PLy_cursor_dealloc(), PLy_plan_dealloc(), PLy_spi_execute_fetch_result(), and PLyObject_ToComposite().

{
    if (arg->is_rowtype == 1)
    {
        int         i;

        for (i = 0; i < arg->in.r.natts; i++)
        {
            if (arg->in.r.atts[i].elm != NULL)
                PLy_free(arg->in.r.atts[i].elm);
        }
        if (arg->in.r.atts)
            PLy_free(arg->in.r.atts);
        for (i = 0; i < arg->out.r.natts; i++)
        {
            if (arg->out.r.atts[i].elm != NULL)
                PLy_free(arg->out.r.atts[i].elm);
        }
        if (arg->out.r.atts)
            PLy_free(arg->out.r.atts);
    }
}

void PLy_typeinfo_init ( PLyTypeInfo arg  ) 
static PyObject * PLyBool_FromBool ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 493 of file plpy_typeio.c.

References DatumGetBool.

{
    /*
     * We would like to use Py_RETURN_TRUE and Py_RETURN_FALSE here for
     * generating SQL from trigger functions, but those are only supported in
     * Python >= 2.4, and we support older versions.
     * http://docs.python.org/api/boolObjects.html
     */
    if (DatumGetBool(d))
        return PyBool_FromLong(1);
    return PyBool_FromLong(0);
}

static PyObject * PLyBytes_FromBytea ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 560 of file plpy_typeio.c.

References DatumGetByteaP, PyBytes_FromStringAndSize, VARDATA, and VARSIZE.

{
    text       *txt = DatumGetByteaP(d);
    char       *str = VARDATA(txt);
    size_t      size = VARSIZE(txt) - VARHDRSZ;

    return PyBytes_FromStringAndSize(str, size);
}

PyObject* PLyDict_FromTuple ( PLyTypeInfo info,
HeapTuple  tuple,
TupleDesc  desc 
)

Definition at line 281 of file plpy_typeio.c.

References tupleDesc::attrs, PLyTupleToOb::atts, CurrentMemoryContext, elog, ERROR, PLyDatumToOb::func, heap_getattr, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, MemoryContextReset(), MemoryContextSwitchTo(), NameStr, PLyTupleToOb::natts, NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_current_execution_context(), PLy_elog(), PLyTypeInput::r, PLyExecutionContext::scratch_ctx, and value.

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_function_build_args(), PLy_spi_execute_fetch_result(), and PLy_trigger_build_args().

{
    PyObject   *volatile dict;
    PLyExecutionContext *exec_ctx = PLy_current_execution_context();
    MemoryContext oldcontext = CurrentMemoryContext;
    int         i;

    if (info->is_rowtype != 1)
        elog(ERROR, "PLyTypeInfo structure describes a datum");

    dict = PyDict_New();
    if (dict == NULL)
        PLy_elog(ERROR, "could not create new dictionary");

    PG_TRY();
    {
        /*
         * Do the work in the scratch context to avoid leaking memory from the
         * datatype output function calls.
         */
        MemoryContextSwitchTo(exec_ctx->scratch_ctx);
        for (i = 0; i < info->in.r.natts; i++)
        {
            char       *key;
            Datum       vattr;
            bool        is_null;
            PyObject   *value;

            if (desc->attrs[i]->attisdropped)
                continue;

            key = NameStr(desc->attrs[i]->attname);
            vattr = heap_getattr(tuple, (i + 1), desc, &is_null);

            if (is_null || info->in.r.atts[i].func == NULL)
                PyDict_SetItemString(dict, key, Py_None);
            else
            {
                value = (info->in.r.atts[i].func) (&info->in.r.atts[i], vattr);
                PyDict_SetItemString(dict, key, value);
                Py_DECREF(value);
            }
        }
        MemoryContextSwitchTo(oldcontext);
        MemoryContextReset(exec_ctx->scratch_ctx);
    }
    PG_CATCH();
    {
        MemoryContextSwitchTo(oldcontext);
        Py_DECREF(dict);
        PG_RE_THROW();
    }
    PG_END_TRY();

    return dict;
}

static PyObject * PLyFloat_FromFloat4 ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 507 of file plpy_typeio.c.

References DatumGetFloat4.

{
    return PyFloat_FromDouble(DatumGetFloat4(d));
}

static PyObject * PLyFloat_FromFloat8 ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 513 of file plpy_typeio.c.

References DatumGetFloat8.

{
    return PyFloat_FromDouble(DatumGetFloat8(d));
}

static PyObject * PLyFloat_FromNumeric ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 519 of file plpy_typeio.c.

References DatumGetFloat8, DirectFunctionCall1, and numeric_float8().

{
    /*
     * Numeric is cast to a PyFloat: This results in a loss of precision Would
     * it be better to cast to PyString?
     */
    Datum       f = DirectFunctionCall1(numeric_float8, d);
    double      x = DatumGetFloat8(f);

    return PyFloat_FromDouble(x);
}

static Datum PLyGenericObject_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  object 
) [static]

Definition at line 1008 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_form_tuple(), HeapTupleGetDatum, i, PLyTypeInfo::is_rowtype, NameStr, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, ReleaseTupleDesc, value, and values.

Referenced by PLyObject_ToCompositeDatum().

{
    HeapTuple   tuple;
    Datum      *values;
    bool       *nulls;
    volatile int i;

    if (info->is_rowtype == 2)
        PLy_output_tuple_funcs(info, desc);
    Assert(info->is_rowtype == 1);

    /* Build tuple */
    values = palloc(sizeof(Datum) * desc->natts);
    nulls = palloc(sizeof(bool) * desc->natts);
    for (i = 0; i < desc->natts; ++i)
    {
        char       *key;
        PyObject   *volatile value;
        PLyObToDatum *att;

        if (desc->attrs[i]->attisdropped)
        {
            values[i] = (Datum) 0;
            nulls[i] = true;
            continue;
        }

        key = NameStr(desc->attrs[i]->attname);
        value = NULL;
        att = &info->out.r.atts[i];
        PG_TRY();
        {
            value = PyObject_GetAttrString(object, key);
            if (value == Py_None)
            {
                values[i] = (Datum) NULL;
                nulls[i] = true;
            }
            else if (value)
            {
                values[i] = (att->func) (att, -1, value);
                nulls[i] = false;
            }
            else
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_COLUMN),
                         errmsg("attribute \"%s\" does not exist in Python object", key),
                         errhint("To return null in a column, "
                           "let the returned object have an attribute named "
                                 "after column with value None.")));

            Py_XDECREF(value);
            value = NULL;
        }
        PG_CATCH();
        {
            Py_XDECREF(value);
            PG_RE_THROW();
        }
        PG_END_TRY();
    }

    tuple = heap_form_tuple(desc, values, nulls);
    ReleaseTupleDesc(desc);
    pfree(values);
    pfree(nulls);

    return HeapTupleGetDatum(tuple);
}

static PyObject * PLyInt_FromInt16 ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 532 of file plpy_typeio.c.

References DatumGetInt16.

{
    return PyInt_FromLong(DatumGetInt16(d));
}

static PyObject * PLyInt_FromInt32 ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 538 of file plpy_typeio.c.

References DatumGetInt32.

{
    return PyInt_FromLong(DatumGetInt32(d));
}

static PyObject * PLyList_FromArray ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 580 of file plpy_typeio.c.

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, array_ref(), DatumGetArrayTypeP, PLyDatumToOb::elm, ereport, errcode(), errdetail(), errmsg(), ERROR, PLyDatumToOb::func, i, sort-test::list, NULL, PLy_elog(), PLyDatumToOb::typalign, PLyDatumToOb::typbyval, and PLyDatumToOb::typlen.

{
    ArrayType  *array = DatumGetArrayTypeP(d);
    PLyDatumToOb *elm = arg->elm;
    PyObject   *list;
    int         length;
    int         lbound;
    int         i;

    if (ARR_NDIM(array) == 0)
        return PyList_New(0);

    if (ARR_NDIM(array) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
              errmsg("cannot convert multidimensional array to Python list"),
              errdetail("PL/Python only supports one-dimensional arrays.")));

    length = ARR_DIMS(array)[0];
    lbound = ARR_LBOUND(array)[0];
    list = PyList_New(length);
    if (list == NULL)
        PLy_elog(ERROR, "could not create new Python list");

    for (i = 0; i < length; i++)
    {
        Datum       elem;
        bool        isnull;
        int         offset;

        offset = lbound + i;
        elem = array_ref(array, 1, &offset, arg->typlen,
                         elm->typlen, elm->typbyval, elm->typalign,
                         &isnull);
        if (isnull)
        {
            Py_INCREF(Py_None);
            PyList_SET_ITEM(list, i, Py_None);
        }
        else
            PyList_SET_ITEM(list, i, elm->func(elm, elem));
    }

    return list;
}

static PyObject * PLyLong_FromInt64 ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 544 of file plpy_typeio.c.

References DatumGetInt64.

{
    /* on 32 bit platforms "long" may be too small */
    if (sizeof(int64) > sizeof(long))
        return PyLong_FromLongLong(DatumGetInt64(d));
    else
        return PyLong_FromLong(DatumGetInt64(d));
}

static PyObject * PLyLong_FromOid ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 554 of file plpy_typeio.c.

References DatumGetObjectId.

{
    return PyLong_FromUnsignedLong(DatumGetObjectId(d));
}

static Datum PLyMapping_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  mapping 
) [static]

Definition at line 849 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errhint(), errmsg(), ERROR, PLyObToDatum::func, heap_form_tuple(), HeapTupleGetDatum, i, PLyTypeInfo::is_rowtype, NameStr, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, ReleaseTupleDesc, value, and values.

Referenced by PLyObject_ToCompositeDatum().

{
    HeapTuple   tuple;
    Datum      *values;
    bool       *nulls;
    volatile int i;

    Assert(PyMapping_Check(mapping));

    if (info->is_rowtype == 2)
        PLy_output_tuple_funcs(info, desc);
    Assert(info->is_rowtype == 1);

    /* Build tuple */
    values = palloc(sizeof(Datum) * desc->natts);
    nulls = palloc(sizeof(bool) * desc->natts);
    for (i = 0; i < desc->natts; ++i)
    {
        char       *key;
        PyObject   *volatile value;
        PLyObToDatum *att;

        if (desc->attrs[i]->attisdropped)
        {
            values[i] = (Datum) 0;
            nulls[i] = true;
            continue;
        }

        key = NameStr(desc->attrs[i]->attname);
        value = NULL;
        att = &info->out.r.atts[i];
        PG_TRY();
        {
            value = PyMapping_GetItemString(mapping, key);
            if (value == Py_None)
            {
                values[i] = (Datum) NULL;
                nulls[i] = true;
            }
            else if (value)
            {
                values[i] = (att->func) (att, -1, value);
                nulls[i] = false;
            }
            else
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_COLUMN),
                         errmsg("key \"%s\" not found in mapping", key),
                         errhint("To return null in a column, "
                                 "add the value None to the mapping with the key named after the column.")));

            Py_XDECREF(value);
            value = NULL;
        }
        PG_CATCH();
        {
            Py_XDECREF(value);
            PG_RE_THROW();
        }
        PG_END_TRY();
    }

    tuple = heap_form_tuple(desc, values, nulls);
    ReleaseTupleDesc(desc);
    pfree(values);
    pfree(nulls);

    return HeapTupleGetDatum(tuple);
}

static Datum PLyObject_ToBool ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv 
) [static]

Definition at line 633 of file plpy_typeio.c.

References Assert, BoolGetDatum, domain_check(), FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typtype(), PLyObToDatum::typfunc, PLyObToDatum::typoid, and TYPTYPE_DOMAIN.

{
    Datum       rv;

    Assert(plrv != Py_None);
    rv = BoolGetDatum(PyObject_IsTrue(plrv));

    if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
        domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);

    return rv;
}

static Datum PLyObject_ToBytea ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv 
) [static]

Definition at line 652 of file plpy_typeio.c.

References Assert, domain_check(), ERROR, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typtype(), palloc(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_elog(), PointerGetDatum, PyBytes_AsString, PyBytes_Size, PyObject_Bytes, SET_VARSIZE, PLyObToDatum::typfunc, PLyObToDatum::typoid, TYPTYPE_DOMAIN, and VARDATA.

{
    PyObject   *volatile plrv_so = NULL;
    Datum       rv;

    Assert(plrv != Py_None);

    plrv_so = PyObject_Bytes(plrv);
    if (!plrv_so)
        PLy_elog(ERROR, "could not create bytes representation of Python object");

    PG_TRY();
    {
        char       *plrv_sc = PyBytes_AsString(plrv_so);
        size_t      len = PyBytes_Size(plrv_so);
        size_t      size = len + VARHDRSZ;
        bytea      *result = palloc(size);

        SET_VARSIZE(result, size);
        memcpy(VARDATA(result), plrv_sc, len);
        rv = PointerGetDatum(result);
    }
    PG_CATCH();
    {
        Py_XDECREF(plrv_so);
        PG_RE_THROW();
    }
    PG_END_TRY();

    Py_XDECREF(plrv_so);

    if (get_typtype(arg->typoid) == TYPTYPE_DOMAIN)
        domain_check(rv, false, arg->typoid, &arg->typfunc.fn_extra, arg->typfunc.fn_mcxt);

    return rv;
}

static Datum PLyObject_ToComposite ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv 
) [static]

Definition at line 696 of file plpy_typeio.c.

References elog, ERROR, PLyTypeInfo::is_rowtype, lookup_rowtype_tupdesc(), MemSet, PLy_typeinfo_dealloc(), PLy_typeinfo_init(), PLyObject_ToCompositeDatum(), PLyObToDatum::typmod, and PLyObToDatum::typoid.

{
    Datum       rv;
    PLyTypeInfo info;
    TupleDesc   desc;

    if (typmod != -1)
        elog(ERROR, "received unnamed record type as input");

    /* Create a dummy PLyTypeInfo */
    MemSet(&info, 0, sizeof(PLyTypeInfo));
    PLy_typeinfo_init(&info);
    /* Mark it as needing output routines lookup */
    info.is_rowtype = 2;

    desc = lookup_rowtype_tupdesc(arg->typoid, arg->typmod);

    /*
     * This will set up the dummy PLyTypeInfo's output conversion routines,
     * since we left is_rowtype as 2. A future optimisation could be caching
     * that info instead of looking it up every time a tuple is returned from
     * the function.
     */
    rv = PLyObject_ToCompositeDatum(&info, desc, plrv);

    PLy_typeinfo_dealloc(&info);

    return rv;
}

Datum PLyObject_ToCompositeDatum ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  plrv 
)

Definition at line 344 of file plpy_typeio.c.

References PLyGenericObject_ToComposite(), PLyMapping_ToComposite(), PLySequence_ToComposite(), and PLyString_ToComposite().

Referenced by PLy_exec_function(), and PLyObject_ToComposite().

{
    Datum       datum;

    if (PyString_Check(plrv) || PyUnicode_Check(plrv))
        datum = PLyString_ToComposite(info, desc, plrv);
    else if (PySequence_Check(plrv))
        /* composite type as sequence (tuple, list etc) */
        datum = PLySequence_ToComposite(info, desc, plrv);
    else if (PyMapping_Check(plrv))
        /* composite type as mapping (currently only dict) */
        datum = PLyMapping_ToComposite(info, desc, plrv);
    else
        /* returned as smth, must provide method __getattr__(name) */
        datum = PLyGenericObject_ToComposite(info, desc, plrv);

    return datum;
}

static Datum PLyObject_ToDatum ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv 
) [static]

Definition at line 732 of file plpy_typeio.c.

References Assert, elog, ereport, errcode(), errmsg(), ERROR, InputFunctionCall(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_verifymbstr(), PLy_elog(), PLyUnicode_Bytes(), PyBytes_AsString, PyBytes_Size, PLyObToDatum::typfunc, and PLyObToDatum::typioparam.

Referenced by PLyString_ToComposite().

{
    PyObject   *volatile plrv_bo = NULL;
    Datum       rv;

    Assert(plrv != Py_None);

    if (PyUnicode_Check(plrv))
        plrv_bo = PLyUnicode_Bytes(plrv);
    else
    {
#if PY_MAJOR_VERSION >= 3
        PyObject   *s = PyObject_Str(plrv);

        plrv_bo = PLyUnicode_Bytes(s);
        Py_XDECREF(s);
#else
        plrv_bo = PyObject_Str(plrv);
#endif
    }
    if (!plrv_bo)
        PLy_elog(ERROR, "could not create string representation of Python object");

    PG_TRY();
    {
        char       *plrv_sc = PyBytes_AsString(plrv_bo);
        size_t      plen = PyBytes_Size(plrv_bo);
        size_t      slen = strlen(plrv_sc);

        if (slen < plen)
            ereport(ERROR,
                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                     errmsg("could not convert Python object into cstring: Python string representation appears to contain null bytes")));
        else if (slen > plen)
            elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
        pg_verifymbstr(plrv_sc, slen, false);
        rv = InputFunctionCall(&arg->typfunc,
                               plrv_sc,
                               arg->typioparam,
                               typmod);
    }
    PG_CATCH();
    {
        Py_XDECREF(plrv_bo);
        PG_RE_THROW();
    }
    PG_END_TRY();

    Py_XDECREF(plrv_bo);

    return rv;
}

static Datum PLySequence_ToArray ( PLyObToDatum arg,
int32  typmod,
PyObject *  plrv 
) [static]

Definition at line 786 of file plpy_typeio.c.

References Assert, construct_md_array(), PLyObToDatum::elm, ERROR, PLyObToDatum::func, get_element_type(), i, palloc(), PLy_elog(), PointerGetDatum, PLyObToDatum::typalign, PLyObToDatum::typbyval, PLyObToDatum::typlen, and PLyObToDatum::typoid.

{
    ArrayType  *array;
    int         i;
    Datum      *elems;
    bool       *nulls;
    int         len;
    int         lbs;

    Assert(plrv != Py_None);

    if (!PySequence_Check(plrv))
        PLy_elog(ERROR, "return value of function with array return type is not a Python sequence");

    len = PySequence_Length(plrv);
    elems = palloc(sizeof(*elems) * len);
    nulls = palloc(sizeof(*nulls) * len);

    for (i = 0; i < len; i++)
    {
        PyObject   *obj = PySequence_GetItem(plrv, i);

        if (obj == Py_None)
            nulls[i] = true;
        else
        {
            nulls[i] = false;

            /*
             * We don't support arrays of row types yet, so the first argument
             * can be NULL.
             */
            elems[i] = arg->elm->func(arg->elm, -1, obj);
        }
        Py_XDECREF(obj);
    }

    lbs = 1;
    array = construct_md_array(elems, nulls, 1, &len, &lbs,
                               get_element_type(arg->typoid), arg->elm->typlen, arg->elm->typbyval, arg->elm->typalign);
    return PointerGetDatum(array);
}

static Datum PLySequence_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  sequence 
) [static]

Definition at line 922 of file plpy_typeio.c.

References Assert, tupleDesc::attrs, PLyObToTuple::atts, ereport, errcode(), errmsg(), ERROR, PLyObToDatum::func, heap_form_tuple(), HeapTupleGetDatum, i, PLyTypeInfo::is_rowtype, tupleDesc::natts, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_output_tuple_funcs(), PLyTypeOutput::r, ReleaseTupleDesc, value, and values.

Referenced by PLyObject_ToCompositeDatum().

{
    HeapTuple   tuple;
    Datum      *values;
    bool       *nulls;
    volatile int idx;
    volatile int i;

    Assert(PySequence_Check(sequence));

    /*
     * Check that sequence length is exactly same as PG tuple's. We actually
     * can ignore exceeding items or assume missing ones as null but to avoid
     * plpython developer's errors we are strict here
     */
    idx = 0;
    for (i = 0; i < desc->natts; i++)
    {
        if (!desc->attrs[i]->attisdropped)
            idx++;
    }
    if (PySequence_Length(sequence) != idx)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("length of returned sequence did not match number of columns in row")));

    if (info->is_rowtype == 2)
        PLy_output_tuple_funcs(info, desc);
    Assert(info->is_rowtype == 1);

    /* Build tuple */
    values = palloc(sizeof(Datum) * desc->natts);
    nulls = palloc(sizeof(bool) * desc->natts);
    idx = 0;
    for (i = 0; i < desc->natts; ++i)
    {
        PyObject   *volatile value;
        PLyObToDatum *att;

        if (desc->attrs[i]->attisdropped)
        {
            values[i] = (Datum) 0;
            nulls[i] = true;
            continue;
        }

        value = NULL;
        att = &info->out.r.atts[i];
        PG_TRY();
        {
            value = PySequence_GetItem(sequence, idx);
            Assert(value);
            if (value == Py_None)
            {
                values[i] = (Datum) NULL;
                nulls[i] = true;
            }
            else if (value)
            {
                values[i] = (att->func) (att, -1, value);
                nulls[i] = false;
            }

            Py_XDECREF(value);
            value = NULL;
        }
        PG_CATCH();
        {
            Py_XDECREF(value);
            PG_RE_THROW();
        }
        PG_END_TRY();

        idx++;
    }

    tuple = heap_form_tuple(desc, values, nulls);
    ReleaseTupleDesc(desc);
    pfree(values);
    pfree(nulls);

    return HeapTupleGetDatum(tuple);
}

static PyObject * PLyString_FromDatum ( PLyDatumToOb arg,
Datum  d 
) [static]

Definition at line 570 of file plpy_typeio.c.

References OutputFunctionCall(), pfree(), and PLyDatumToOb::typfunc.

{
    char       *x = OutputFunctionCall(&arg->typfunc, d);
    PyObject   *r = PyString_FromString(x);

    pfree(x);
    return r;
}

static Datum PLyString_ToComposite ( PLyTypeInfo info,
TupleDesc  desc,
PyObject *  string 
) [static]