#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"
Go to the source code of this file.
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 | ) |
Definition at line 64 of file plpy_typeio.c.
References PLyObToTuple::atts, PLyTupleToOb::atts, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, ItemPointerSetInvalid, PLyObToTuple::natts, PLyTupleToOb::natts, PLyTypeInfo::out, PLyTypeOutput::r, PLyTypeInput::r, PLyTypeInfo::typ_relid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.
Referenced by PLy_cursor_plan(), PLy_cursor_query(), PLy_procedure_create(), PLy_spi_execute_fetch_result(), PLy_spi_prepare(), and PLyObject_ToComposite().
{ arg->is_rowtype = -1; arg->in.r.natts = arg->out.r.natts = 0; arg->in.r.atts = NULL; arg->out.r.atts = NULL; arg->typ_relid = InvalidOid; arg->typrel_xmin = InvalidTransactionId; ItemPointerSetInvalid(&arg->typrel_tid); }
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] |
Definition at line 831 of file plpy_typeio.c.
References PLyTypeOutput::d, elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, PLyTypeInfo::out, PLy_output_datum_func2(), PLyObject_ToDatum(), ReleaseSysCache(), ReleaseTupleDesc, SearchSysCache1, tupleDesc::tdtypeid, TYPEOID, and PLyObToDatum::typmod.
Referenced by PLyObject_ToCompositeDatum().
{ HeapTuple typeTup; typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid); PLy_output_datum_func2(&info->out.d, typeTup); ReleaseSysCache(typeTup); ReleaseTupleDesc(desc); return PLyObject_ToDatum(&info->out.d, info->out.d.typmod, string); }