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

Reply via email to