@ -32,6 +32,7 @@ typedef struct ColumnIOData
Oid column_type ;
Oid column_type ;
Oid typiofunc ;
Oid typiofunc ;
Oid typioparam ;
Oid typioparam ;
bool typisvarlena ;
FmgrInfo proc ;
FmgrInfo proc ;
} ColumnIOData ;
} ColumnIOData ;
@ -340,6 +341,7 @@ record_out(PG_FUNCTION_ARGS)
{
{
ColumnIOData * column_info = & my_extra - > columns [ i ] ;
ColumnIOData * column_info = & my_extra - > columns [ i ] ;
Oid column_type = tupdesc - > attrs [ i ] - > atttypid ;
Oid column_type = tupdesc - > attrs [ i ] - > atttypid ;
Datum attr ;
char * value ;
char * value ;
char * tmp ;
char * tmp ;
bool nq ;
bool nq ;
@ -363,17 +365,24 @@ record_out(PG_FUNCTION_ARGS)
*/
*/
if ( column_info - > column_type ! = column_type )
if ( column_info - > column_type ! = column_type )
{
{
bool typIsVarlena ;
getTypeOutputInfo ( column_type ,
getTypeOutputInfo ( column_type ,
& column_info - > typiofunc ,
& column_info - > typiofunc ,
& typIsV arlena) ;
& column_info - > typisv arlena) ;
fmgr_info_cxt ( column_info - > typiofunc , & column_info - > proc ,
fmgr_info_cxt ( column_info - > typiofunc , & column_info - > proc ,
fcinfo - > flinfo - > fn_mcxt ) ;
fcinfo - > flinfo - > fn_mcxt ) ;
column_info - > column_type = column_type ;
column_info - > column_type = column_type ;
}
}
value = OutputFunctionCall ( & column_info - > proc , values [ i ] ) ;
/*
* If we have a toasted datum , forcibly detoast it here to avoid
* memory leakage inside the type ' s output routine .
*/
if ( column_info - > typisvarlena )
attr = PointerGetDatum ( PG_DETOAST_DATUM ( values [ i ] ) ) ;
else
attr = values [ i ] ;
value = OutputFunctionCall ( & column_info - > proc , attr ) ;
/* Detect whether we need double quotes for this value */
/* Detect whether we need double quotes for this value */
nq = ( value [ 0 ] = = ' \0 ' ) ; /* force quotes for empty string */
nq = ( value [ 0 ] = = ' \0 ' ) ; /* force quotes for empty string */
@ -392,17 +401,23 @@ record_out(PG_FUNCTION_ARGS)
/* And emit the string */
/* And emit the string */
if ( nq )
if ( nq )
appendStringInfoChar ( & buf , ' " ' ) ;
appendStringInfoCharMacro ( & buf , ' " ' ) ;
for ( tmp = value ; * tmp ; tmp + + )
for ( tmp = value ; * tmp ; tmp + + )
{
{
char ch = * tmp ;
char ch = * tmp ;
if ( ch = = ' " ' | | ch = = ' \\ ' )
if ( ch = = ' " ' | | ch = = ' \\ ' )
appendStringInfoChar ( & buf , ch ) ;
appendStringInfoCharMacro ( & buf , ch ) ;
appendStringInfoChar ( & buf , ch ) ;
appendStringInfoCharMacro ( & buf , ch ) ;
}
}
if ( nq )
if ( nq )
appendStringInfoChar ( & buf , ' " ' ) ;
appendStringInfoCharMacro ( & buf , ' " ' ) ;
pfree ( value ) ;
/* Clean up detoasted copy, if any */
if ( DatumGetPointer ( attr ) ! = DatumGetPointer ( values [ i ] ) )
pfree ( DatumGetPointer ( attr ) ) ;
}
}
appendStringInfoChar ( & buf , ' ) ' ) ;
appendStringInfoChar ( & buf , ' ) ' ) ;
@ -690,6 +705,7 @@ record_send(PG_FUNCTION_ARGS)
{
{
ColumnIOData * column_info = & my_extra - > columns [ i ] ;
ColumnIOData * column_info = & my_extra - > columns [ i ] ;
Oid column_type = tupdesc - > attrs [ i ] - > atttypid ;
Oid column_type = tupdesc - > attrs [ i ] - > atttypid ;
Datum attr ;
bytea * outputbytes ;
bytea * outputbytes ;
/* Ignore dropped columns in datatype */
/* Ignore dropped columns in datatype */
@ -710,23 +726,35 @@ record_send(PG_FUNCTION_ARGS)
*/
*/
if ( column_info - > column_type ! = column_type )
if ( column_info - > column_type ! = column_type )
{
{
bool typIsVarlena ;
getTypeBinaryOutputInfo ( column_type ,
getTypeBinaryOutputInfo ( column_type ,
& column_info - > typiofunc ,
& column_info - > typiofunc ,
& typIsV arlena) ;
& column_info - > typisv arlena) ;
fmgr_info_cxt ( column_info - > typiofunc , & column_info - > proc ,
fmgr_info_cxt ( column_info - > typiofunc , & column_info - > proc ,
fcinfo - > flinfo - > fn_mcxt ) ;
fcinfo - > flinfo - > fn_mcxt ) ;
column_info - > column_type = column_type ;
column_info - > column_type = column_type ;
}
}
outputbytes = SendFunctionCall ( & column_info - > proc , values [ i ] ) ;
/*
* If we have a toasted datum , forcibly detoast it here to avoid
* memory leakage inside the type ' s output routine .
*/
if ( column_info - > typisvarlena )
attr = PointerGetDatum ( PG_DETOAST_DATUM ( values [ i ] ) ) ;
else
attr = values [ i ] ;
outputbytes = SendFunctionCall ( & column_info - > proc , attr ) ;
/* We assume the result will not have been toasted */
/* We assume the result will not have been toasted */
pq_sendint ( & buf , VARSIZE ( outputbytes ) - VARHDRSZ , 4 ) ;
pq_sendint ( & buf , VARSIZE ( outputbytes ) - VARHDRSZ , 4 ) ;
pq_sendbytes ( & buf , VARDATA ( outputbytes ) ,
pq_sendbytes ( & buf , VARDATA ( outputbytes ) ,
VARSIZE ( outputbytes ) - VARHDRSZ ) ;
VARSIZE ( outputbytes ) - VARHDRSZ ) ;
pfree ( outputbytes ) ;
pfree ( outputbytes ) ;
/* Clean up detoasted copy, if any */
if ( DatumGetPointer ( attr ) ! = DatumGetPointer ( values [ i ] ) )
pfree ( DatumGetPointer ( attr ) ) ;
}
}
pfree ( values ) ;
pfree ( values ) ;