@ -29,8 +29,8 @@
/* I/O function caching */
static void PLy_input_datum_func2 ( PLyDatumToOb * arg , Oid typeOid , HeapTuple typeTup , Oid langid , List * trftypes ) ;
static void PLy_output_datum_func2 ( PLyObToDatum * arg , HeapTuple typeTup , Oid langid , List * trftypes ) ;
static void PLy_input_datum_func2 ( PLyDatumToOb * arg , MemoryContext arg_mcxt , Oid typeOid , HeapTuple typeTup , Oid langid , List * trftypes ) ;
static void PLy_output_datum_func2 ( PLyObToDatum * arg , MemoryContext arg_mcxt , HeapTuple typeTup , Oid langid , List * trftypes ) ;
/* conversion from Datums to Python objects */
static PyObject * PLyBool_FromBool ( PLyDatumToOb * arg , Datum d ) ;
@ -60,11 +60,8 @@ static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject
static Datum PLySequence_ToComposite ( PLyTypeInfo * info , TupleDesc desc , PyObject * sequence ) ;
static Datum PLyGenericObject_ToComposite ( PLyTypeInfo * info , TupleDesc desc , PyObject * object ) ;
/* make allocations in the TopMemoryContext */
static void perm_fmgr_info ( Oid functionId , FmgrInfo * finfo ) ;
void
PLy_typeinfo_init ( PLyTypeInfo * arg )
PLy_typeinfo_init ( PLyTypeInfo * arg , MemoryContext mcxt )
{
arg - > is_rowtype = - 1 ;
arg - > in . r . natts = arg - > out . r . natts = 0 ;
@ -73,30 +70,7 @@ PLy_typeinfo_init(PLyTypeInfo *arg)
arg - > typ_relid = InvalidOid ;
arg - > typrel_xmin = InvalidTransactionId ;
ItemPointerSetInvalid ( & arg - > typrel_tid ) ;
}
void
PLy_typeinfo_dealloc ( PLyTypeInfo * arg )
{
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 ) ;
}
arg - > mcxt = mcxt ;
}
/*
@ -109,7 +83,7 @@ PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langi
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 , langid , trftypes ) ;
PLy_input_datum_func2 ( & ( arg - > in . d ) , arg - > mcxt , typeOid , typeTup , langid , trftypes ) ;
}
void
@ -118,7 +92,7 @@ PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trf
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 , langid , trftypes ) ;
PLy_output_datum_func2 ( & ( arg - > out . d ) , arg - > mcxt , typeTup , langid , trftypes ) ;
}
void
@ -126,6 +100,9 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
{
int i ;
PLyExecutionContext * exec_ctx = PLy_current_execution_context ( ) ;
MemoryContext oldcxt ;
oldcxt = MemoryContextSwitchTo ( arg - > mcxt ) ;
if ( arg - > is_rowtype = = 0 )
elog ( ERROR , " PLyTypeInfo struct is initialized for a Datum " ) ;
@ -134,9 +111,9 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
if ( arg - > in . r . natts ! = desc - > natts )
{
if ( arg - > in . r . atts )
PLy_ free( arg - > in . r . atts ) ;
p free( arg - > in . r . atts ) ;
arg - > in . r . natts = desc - > natts ;
arg - > in . r . atts = PLy_m alloc0( desc - > natts * sizeof ( PLyDatumToOb ) ) ;
arg - > in . r . atts = p alloc0( desc - > natts * sizeof ( PLyDatumToOb ) ) ;
}
/* Can this be an unnamed tuple? If not, then an Assert would be enough */
@ -182,7 +159,7 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
elog ( ERROR , " cache lookup failed for type %u " ,
desc - > attrs [ i ] - > atttypid ) ;
PLy_input_datum_func2 ( & ( arg - > in . r . atts [ i ] ) ,
PLy_input_datum_func2 ( & ( arg - > in . r . atts [ i ] ) , arg - > mcxt ,
desc - > attrs [ i ] - > atttypid ,
typeTup ,
exec_ctx - > curr_proc - > langid ,
@ -190,6 +167,8 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
ReleaseSysCache ( typeTup ) ;
}
MemoryContextSwitchTo ( oldcxt ) ;
}
void
@ -197,6 +176,9 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
{
int i ;
PLyExecutionContext * exec_ctx = PLy_current_execution_context ( ) ;
MemoryContext oldcxt ;
oldcxt = MemoryContextSwitchTo ( arg - > mcxt ) ;
if ( arg - > is_rowtype = = 0 )
elog ( ERROR , " PLyTypeInfo struct is initialized for a Datum " ) ;
@ -205,9 +187,9 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
if ( arg - > out . r . natts ! = desc - > natts )
{
if ( arg - > out . r . atts )
PLy_ free( arg - > out . r . atts ) ;
p free( arg - > out . r . atts ) ;
arg - > out . r . natts = desc - > natts ;
arg - > out . r . atts = PLy_m alloc0( desc - > natts * sizeof ( PLyObToDatum ) ) ;
arg - > out . r . atts = p alloc0( desc - > natts * sizeof ( PLyObToDatum ) ) ;
}
Assert ( OidIsValid ( desc - > tdtypeid ) ) ;
@ -249,12 +231,14 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
elog ( ERROR , " cache lookup failed for type %u " ,
desc - > attrs [ i ] - > atttypid ) ;
PLy_output_datum_func2 ( & ( arg - > out . r . atts [ i ] ) , typeTup ,
PLy_output_datum_func2 ( & ( arg - > out . r . atts [ i ] ) , arg - > mcxt , typeTup ,
exec_ctx - > curr_proc - > langid ,
exec_ctx - > curr_proc - > trftypes ) ;
ReleaseSysCache ( typeTup ) ;
}
MemoryContextSwitchTo ( oldcxt ) ;
}
void
@ -291,8 +275,8 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
{
PyObject * volatile dict ;
PLyExecutionContext * exec_ctx = PLy_current_execution_context ( ) ;
MemoryContext scratch_context = PLy_get_scratch_context ( exec_ctx ) ;
MemoryContext oldcontext = CurrentMemoryContext ;
int i ;
if ( info - > is_rowtype ! = 1 )
elog ( ERROR , " PLyTypeInfo structure describes a datum " ) ;
@ -303,11 +287,13 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
PG_TRY ( ) ;
{
int i ;
/*
* Do the work in the scratch context to avoid leaking memory from the
* datatype output function calls .
*/
MemoryContextSwitchTo ( exec_ctx - > scratch_ctx ) ;
MemoryContextSwitchTo ( scratch_con te xt ) ;
for ( i = 0 ; i < info - > in . r . natts ; i + + )
{
char * key ;
@ -331,7 +317,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
}
}
MemoryContextSwitchTo ( oldcontext ) ;
MemoryContextReset ( exec_ctx - > scratch_ctx ) ;
MemoryContextReset ( scratch_con te xt ) ;
}
PG_CATCH ( ) ;
{
@ -370,14 +356,17 @@ PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
}
static void
PLy_output_datum_func2 ( PLyObToDatum * arg , HeapTuple typeTup , Oid langid , List * trftypes )
PLy_output_datum_func2 ( PLyObToDatum * arg , MemoryContext arg_mcxt , HeapTuple typeTup , Oid langid , List * trftypes )
{
Form_pg_type typeStruct = ( Form_pg_type ) GETSTRUCT ( typeTup ) ;
Oid element_type ;
Oid base_type ;
Oid funcid ;
MemoryContext oldcxt ;
perm_fmgr_info ( typeStruct - > typinput , & arg - > typfunc ) ;
oldcxt = MemoryContextSwitchTo ( arg_mcxt ) ;
fmgr_info_cxt ( typeStruct - > typinput , & arg - > typfunc , arg_mcxt ) ;
arg - > typoid = HeapTupleGetOid ( typeTup ) ;
arg - > typmod = - 1 ;
arg - > typioparam = getTypeIOParam ( typeTup ) ;
@ -394,7 +383,7 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t
if ( ( funcid = get_transform_tosql ( base_type , langid , trftypes ) ) )
{
arg - > func = PLyObject_ToTransform ;
perm_ fmgr_info( funcid , & arg - > typtransform ) ;
fmgr_info_cxt ( funcid , & arg - > typtransform , arg_mcxt ) ;
}
else if ( typeStruct - > typtype = = TYPTYPE_COMPOSITE )
{
@ -422,7 +411,7 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t
if ( type_is_rowtype ( element_type ) )
arg - > func = PLyObject_ToComposite ;
arg - > elm = PLy_m alloc0( sizeof ( * arg - > elm ) ) ;
arg - > elm = p alloc0( sizeof ( * arg - > elm ) ) ;
arg - > elm - > func = arg - > func ;
arg - > elm - > typtransform = arg - > typtransform ;
arg - > func = PLySequence_ToArray ;
@ -432,20 +421,25 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t
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 ) ;
fmgr_info_cxt ( funcid , & arg - > elm - > typfunc , arg_mcxt ) ;
}
MemoryContextSwitchTo ( oldcxt ) ;
}
static void
PLy_input_datum_func2 ( PLyDatumToOb * arg , Oid typeOid , HeapTuple typeTup , Oid langid , List * trftypes )
PLy_input_datum_func2 ( PLyDatumToOb * arg , MemoryContext arg_mcxt , Oid typeOid , HeapTuple typeTup , Oid langid , List * trftypes )
{
Form_pg_type typeStruct = ( Form_pg_type ) GETSTRUCT ( typeTup ) ;
Oid element_type ;
Oid base_type ;
Oid funcid ;
MemoryContext oldcxt ;
oldcxt = MemoryContextSwitchTo ( arg_mcxt ) ;
/* Get the type's conversion information */
perm_fmgr_info ( typeStruct - > typoutput , & arg - > typfunc ) ;
fmgr_info_cxt ( typeStruct - > typoutput , & arg - > typfunc , arg_mcxt ) ;
arg - > typoid = HeapTupleGetOid ( typeTup ) ;
arg - > typmod = - 1 ;
arg - > typioparam = getTypeIOParam ( typeTup ) ;
@ -461,7 +455,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
if ( ( funcid = get_transform_fromsql ( base_type , langid , trftypes ) ) )
{
arg - > func = PLyObject_FromTransform ;
perm_ fmgr_info( funcid , & arg - > typtransform ) ;
fmgr_info_cxt ( funcid , & arg - > typtransform , arg_mcxt ) ;
}
else
switch ( base_type )
@ -503,7 +497,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
char dummy_delim ;
Oid funcid ;
arg - > elm = PLy_m alloc0( sizeof ( * arg - > elm ) ) ;
arg - > elm = p alloc0( sizeof ( * arg - > elm ) ) ;
arg - > elm - > func = arg - > func ;
arg - > elm - > typtransform = arg - > typtransform ;
arg - > func = PLyList_FromArray ;
@ -512,8 +506,10 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
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 ) ;
fmgr_info_cxt ( funcid , & arg - > elm - > typfunc , arg_mcxt ) ;
}
MemoryContextSwitchTo ( oldcxt ) ;
}
static PyObject *
@ -752,13 +748,19 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
Datum rv ;
PLyTypeInfo info ;
TupleDesc desc ;
MemoryContext cxt ;
if ( typmod ! = - 1 )
elog ( ERROR , " received unnamed record type as input " ) ;
/* Create a dummy PLyTypeInfo */
cxt = AllocSetContextCreate ( CurrentMemoryContext ,
" PL/Python temp context " ,
ALLOCSET_DEFAULT_MINSIZE ,
ALLOCSET_DEFAULT_INITSIZE ,
ALLOCSET_DEFAULT_MAXSIZE ) ;
MemSet ( & info , 0 , sizeof ( PLyTypeInfo ) ) ;
PLy_typeinfo_init ( & info ) ;
PLy_typeinfo_init ( & info , cxt ) ;
/* Mark it as needing output routines lookup */
info . is_rowtype = 2 ;
@ -774,7 +776,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
ReleaseTupleDesc ( desc ) ;
PLy_typeinfo_dealloc ( & info ) ;
MemoryContextDelete ( cxt ) ;
return rv ;
}
@ -916,16 +918,22 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
HeapTuple typeTup ;
PLyTypeInfo locinfo ;
PLyExecutionContext * exec_ctx = PLy_current_execution_context ( ) ;
MemoryContext cxt ;
/* Create a dummy PLyTypeInfo */
cxt = AllocSetContextCreate ( CurrentMemoryContext ,
" PL/Python temp context " ,
ALLOCSET_DEFAULT_MINSIZE ,
ALLOCSET_DEFAULT_INITSIZE ,
ALLOCSET_DEFAULT_MAXSIZE ) ;
MemSet ( & locinfo , 0 , sizeof ( PLyTypeInfo ) ) ;
PLy_typeinfo_init ( & locinfo ) ;
PLy_typeinfo_init ( & locinfo , cxt ) ;
typeTup = SearchSysCache1 ( TYPEOID , ObjectIdGetDatum ( desc - > tdtypeid ) ) ;
if ( ! HeapTupleIsValid ( typeTup ) )
elog ( ERROR , " cache lookup failed for type %u " , desc - > tdtypeid ) ;
PLy_output_datum_func2 ( & locinfo . out . d , typeTup ,
PLy_output_datum_func2 ( & locinfo . out . d , locinfo . mcxt , typeTup ,
exec_ctx - > curr_proc - > langid ,
exec_ctx - > curr_proc - > trftypes ) ;
@ -933,7 +941,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
result = PLyObject_ToDatum ( & locinfo . out . d , desc - > tdtypmod , string ) ;
PLy_typeinfo_dealloc ( & locinfo ) ;
MemoryContextDelete ( cxt ) ;
return result ;
}
@ -1177,20 +1185,3 @@ PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object
return result ;
}
/*
* This routine is a crock , and so is everyplace that calls it . The problem
* is that the cached form of plpython functions / queries is allocated permanently
* ( mostly via malloc ( ) ) and never released until backend exit . Subsidiary
* data structures such as fmgr info records therefore must live forever
* as well . A better implementation would store all this stuff in a per -
* function memory context that could be reclaimed at need . In the meantime ,
* fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
* it might allocate , and whatever the eventual function might allocate using
* fn_mcxt , will live forever too .
*/
static void
perm_fmgr_info ( Oid functionId , FmgrInfo * finfo )
{
fmgr_info_cxt ( functionId , finfo , TopMemoryContext ) ;
}