The following bug has been logged online:
Bug reference: 5883
Logged by:
Email address: [email protected]
PostgreSQL version: 8.4.7
Operating system: ubuntu lucid
Description: Error when mixing SPI_returntuple with returning regular
HeapTuple
Details:
When creating a server-side C function, things go wrong when I (in the same
function) return some results via SPI_returntuple, and other results by
manually creating HeapTuples. This applies even if the source for both
returns are the same data in the same table.
I get an error message saying "rows returned by function are not all of the
same row type". In the attached example I would have expected to see the
same row twice.
Everything works as I expect if I try to do the same and stick to using only
one of the alternatives.
Example code:
SQL:
CREATE TABLE test (a int, b int);
INSERT INTO test VALUES (1, 2);
CREATE FUNCTION run_test() RETURNS SETOF test AS 'SOMEWHERE/something.so',
'run_test' LANGUAGE C VOLATILE;
SELECT * FROM run_test();
C:
#include <postgres.h>
#include <fmgr.h>
#include <funcapi.h>
#include <executor/spi.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
static const char * query = "SELECT a, b FROM test";
static void get_data_alternative_a(Datum * data_out, bool * isnull)
{
SPI_execute(query, true, 1);
data_out[0] = SPI_getbinval(* SPI_tuptable->vals,
SPI_tuptable->tupdesc, 1,
& isnull[0]);
data_out[1] = SPI_getbinval(* SPI_tuptable->vals,
SPI_tuptable->tupdesc, 2,
& isnull[1]);
}
static Datum get_data_alternative_b()
{
SPI_execute(query, true, 1);
HeapTupleHeader ret = SPI_returntuple(* SPI_tuptable->vals,
SPI_tuptable->tupdesc);
return PointerGetDatum(ret);
}
PG_FUNCTION_INFO_V1(run_test);
Datum run_test(PG_FUNCTION_ARGS)
{
FuncCallContext * funcctx;
int * return_count = NULL;
if ( SRF_IS_FIRSTCALL() )
{
funcctx = SRF_FIRSTCALL_INIT();
SPI_connect();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
TupleDesc tupdesc;
if (get_call_result_type(fcinfo, NULL, &tupdesc) !=
TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg(
"function returning record called in
context "
"that cannot accept type
record")));
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
return_count = (int *) palloc(sizeof(int));
MemoryContextSwitchTo(oldcontext);
* return_count = 0;
funcctx->user_fctx = (void*) return_count;
}
funcctx = SRF_PERCALL_SETUP();
return_count = (int *) funcctx->user_fctx;
Datum ret[2];
bool isnull[2];
switch ( (* return_count) ++ )
{
case 0:
// SRF_RETURN_NEXT(funcctx, get_data_alternative_b());
get_data_alternative_a(ret, isnull);
break;
case 1:
SRF_RETURN_NEXT(funcctx, get_data_alternative_b());
// get_data_alternative_a(ret, isnull);
break;
default:
SPI_finish();
SRF_RETURN_DONE(funcctx);
}
HeapTuple heap_tuple = heap_form_tuple(funcctx->tuple_desc, ret,
isnull);
Datum packed_ret = HeapTupleGetDatum(heap_tuple);
SRF_RETURN_NEXT(funcctx, packed_ret);
}
--
Sent via pgsql-bugs mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs