SELECT from record-returning function causes function code to be executed multiple times - Mailing list pgsql-general

From dbaston
Subject SELECT from record-returning function causes function code to be executed multiple times
Date
Msg-id 1387138720523-5783495.post@n5.nabble.com
Whole thread Raw
Responses Re: SELECT from record-returning function causes function code to be executed multiple times  (David Johnston <polobo@yahoo.com>)
List pgsql-general
Hello,

I have a simple C-language function , SimpleSRF(), that returns RECORDs with
two integer columns.  When I call the function using SELECT (SIMPLESRF()).*,
the function code is being executed twice.  I'm wondering if this is
expected behavior?

The function is defined as:

CREATE OR REPLACE FUNCTION SIMPLESRF(OUT id integer, OUT type integer)
RETURNS SETOF RECORD
AS '$libdir/pg1.dll', 'simplesrf'
LANGUAGE C IMMUTABLE STRICT;

The function follows the basic structure for an SRF in the docs.  I included
some output statements in the function like this so that I could keep track
of the repeated calls.

elog(INFO, "Call %i", funcctx->call_cntr);

Calling the function like this: SELECT (SIMPLESRF()).* gives me the
following messages:

INFO:  Call 0
INFO:  Call 0
INFO:  Call 1
INFO:  Call 1
INFO:  Call 2
INFO:  Call 2
INFO:  Call 3
INFO:  Call 3
INFO:  Call 4
INFO:  Call 4
INFO:  Call 5
INFO:  Call 5

Total query runtime: 18 ms.
5 rows retrieved.

Apparently the function code is being executed twice, once for each column
in the return tuple.

Alternatively, I can call the function like this:  SELECT * FROM SIMPLESRF()
This gives me the messages I'd expect:

INFO:  Call 0
INFO:  Call 1
INFO:  Call 2
INFO:  Call 3
INFO:  Call 4
INFO:  Call 5

Total query runtime: 12 ms.
5 rows retrieved.

Is this expected behavior?  I would think that the function would only need
to be executed once with either calling pattern, especially since it's been
declared as IMMUTABLE.

I do get different plans with the two calling patterns, though I don't know
enough to understand the differences.

EXPLAIN SELECT (SIMPLESRF()).*
"Result  (cost=0.00..5.01 rows=1000 width=0)"

EXPLAIN SELECT * FROM SIMPLESRF()
"Function Scan on simplesrf  (cost=0.00..10.00 rows=1000 width=8)"

Function code, though I don't think it's relevant:

PG_FUNCTION_INFO_V1(simplesrf);
__declspec(dllexport) Datum simplesrf(PG_FUNCTION_ARGS) {
    FuncCallContext *funcctx;
    TupleDesc resultTupleDesc;
    HeapTuple returnTuple;
    Datum returnValues[2];
    bool returnNulls[2] = {false};

    if (SRF_IS_FIRSTCALL()) {
        struct vertex** a;
        MemoryContext oldContext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldContext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        a = (struct vertex**) palloc(4 * sizeof(struct vertex*));

        resultTupleDesc = CreateTemplateTupleDesc(2, false);
        TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "call", INT4OID, -1,
0);
        TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "call2", INT4OID, -1,
0);
        resultTupleDesc = BlessTupleDesc(resultTupleDesc);
        funcctx->tuple_desc = resultTupleDesc;
        funcctx->max_calls = 5;

        MemoryContextSwitchTo(oldContext);
    }

    funcctx = SRF_PERCALL_SETUP();
    resultTupleDesc = funcctx->tuple_desc;
    elog(INFO, "Call %i", funcctx->call_cntr);

    if (funcctx->call_cntr < funcctx->max_calls) {
        returnValues[0] = Int32GetDatum(1);
        returnValues[1] = Int32GetDatum(2);
        returnTuple = heap_form_tuple(resultTupleDesc, returnValues, returnNulls);

        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(returnTuple));
    } else {
        SRF_RETURN_DONE(funcctx);
    }
}



--
View this message in context:
http://postgresql.1045698.n5.nabble.com/SELECT-from-record-returning-function-causes-function-code-to-be-executed-multiple-times-tp5783495.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.


pgsql-general by date:

Previous
From: "Christofer C. Bell"
Date:
Subject: Re: [DOCS] Re: postgresql.org inconsistent (Re: PG replication across DataCenters)
Next
From: David Johnston
Date:
Subject: Re: SELECT from record-returning function causes function code to be executed multiple times