BUG #5883: Error when mixing SPI_returntuple with returning regular HeapTuple

From: "" <vegard(dot)bones(at)met(dot)no>
To: pgsql-bugs(at)postgresql(dot)org
Subject: BUG #5883: Error when mixing SPI_returntuple with returning regular HeapTuple
Date: 2011-02-14 11:40:40
Message-ID: 201102141140.p1EBeeG8060816@wwwmaster.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs


The following bug has been logged online:

Bug reference: 5883
Logged by:
Email address: vegard(dot)bones(at)met(dot)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);
}

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message dba 2011-02-14 11:51:52 Array issue....
Previous Message Jaime Casanova 2011-02-14 07:25:58 Re: