Skip site navigation (1) Skip section navigation (2)

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 (view raw or flat)
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

pgsql-bugs by date

Next:From: dbaDate: 2011-02-14 11:51:52
Subject: Array issue....
Previous:From: Jaime CasanovaDate: 2011-02-14 07:25:58
Subject: Re:

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group