#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);
}
1.7.1