The following bug has been logged online: Bug reference: 5883 Logged by: Email address: vegard.bo...@met.no 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 (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs