Error when defining a set returning function

Started by Esteban Zimanyiover 4 years ago7 messages
#1Esteban Zimanyi
ezimanyi@ulb.ac.be

Dear all

Since I was receiving an error when defining a set returning function, I
borrowed a function from PostgreSQL as follows

/* C definition */
typedef struct testState
{
int current;
int finish;
int step;
} testState;

/**
* test_srf(startval int, endval int, step int)
*/
PG_FUNCTION_INFO_V1(test_srf);
Datum test_srf(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
testState *fctx;
int result; /* the actual return value */

if (SRF_IS_FIRSTCALL())
{
/* Get input values */
int start = PG_GETARG_INT32(0);
int finish = PG_GETARG_INT32(1);
int step = PG_GETARG_INT32(2);
MemoryContext oldcontext;

/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();

/* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

/* quick opt-out if we get nonsensical inputs */
if (step <= 0 || start == finish)
{
funcctx = SRF_PERCALL_SETUP();
SRF_RETURN_DONE(funcctx);
}

/* allocate memory for function context */
fctx = (testState *) palloc0(sizeof(testState));
fctx->current = start;
fctx->finish = finish;
fctx->step = step;

funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext);
}

/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();

/* get state */
fctx = funcctx->user_fctx;

result = fctx->current;
fctx->current += fctx->step;
/* Stop when we have generated all values */
if (fctx->current > fctx->finish)
{
SRF_RETURN_DONE(funcctx);
}

SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
}

/* SQL definition */
CREATE OR REPLACE FUNCTION testSRF(startval int, endval int, step int)
RETURNS SETOF integer
AS 'MODULE_PATHNAME', 'test_srf'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

When I execute this function I obtain

select testSRF(1,10, 2);
ERROR: unrecognized table-function returnMode: 257

select version();
PostgreSQL 13.2 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu
9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit

Any idea what could be wrong ?

Thanks for your help

Esteban

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Esteban Zimanyi (#1)
Re: Error when defining a set returning function

Esteban Zimanyi <ezimanyi@ulb.ac.be> writes:

Since I was receiving an error when defining a set returning function, I
borrowed a function from PostgreSQL as follows
...
When I execute this function I obtain

select testSRF(1,10, 2);
ERROR: unrecognized table-function returnMode: 257

Hmm, I compiled this function up and it works for me:

regression=# select testSRF(1,10, 2);
testsrf
----------
1
3
5
7
(4 rows)

I think your "quick opt-out" code is a bit broken, because it fails to
restore the current memory context; but there's nothing wrong with the
main code path.

Hence, the problem is somewhere else. The first theory that comes
to mind is that you're compiling against Postgres headers that
don't match the server version you're actually loading the code
into. In theory the PG_MODULE_MAGIC infrastructure ought to catch
that, but maybe you've found some creative way to fool that :-(.
One way maybe would be if the headers were from some pre-release
v13 version that wasn't ABI-compatible with 13.0.

Or it could be something else, but I'd counsel looking for build
process mistakes, cause this C code isn't the problem.

regards, tom lane

#3Esteban Zimanyi
ezimanyi@ulb.ac.be
In reply to: Tom Lane (#2)
Re: Error when defining a set returning function

Dear Tom

Many thanks for asking my question so quickly. After your answer, I
downloaded brand new versions of PostgreSQL 13.2, PostGIS 2.5.5, and
compiled/installed with the standard parameters. I didn't get any error
messages in the build. I then recompiled again MobilityDB and got the same
error message.

When debugging the function with gdb, I noticed that the rsinfo variable of
the PostgreSQL function ExecMakeFunctionResultSet is modified in the
macro SRF_RETURN_NEXT causing the problem. Any idea how to solve this?

4353 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
(gdb) up
#1 0x000055b8a871fc56 in ExecMakeFunctionResultSet (fcache=0x55b8a8e6d9a0,
econtext=0x55b8a8e6cfa0,
argContext=0x55b8a9d00dd0, isNull=0x55b8a8e6d930, isDone=0x55b8a8e6d988)
at
/home/esteban/src/postgresql-13.2/build_dir/../src/backend/executor/execSRF.c:614
614 result = FunctionCallInvoke(fcinfo);
(gdb) p rsinfo
$5 = {type = T_ReturnSetInfo, econtext = 0x55b8a8e6cfa0, expectedDesc =
0x55b8a8e6e8f0, allowedModes = 3,
returnMode = SFRM_ValuePerCall, isDone = ExprSingleResult, setResult =
0x0, setDesc = 0x0}
(gdb) n
4354 }
(gdb)
ExecMakeFunctionResultSet (fcache=0x55b8a8e6d9a0, econtext=0x55b8a8e6cfa0,
argContext=0x55b8a9d00dd0,
isNull=0x55b8a8e6d930, isDone=0x55b8a8e6d988)
at
/home/esteban/src/postgresql-13.2/build_dir/../src/backend/executor/execSRF.c:615
615 *isNull = fcinfo->isnull;
(gdb) p rsinfo
$6 = {type = T_ReturnSetInfo, econtext = 0x55b8a8e6cfa0, expectedDesc =
0x55b8a8e6e8f0, allowedModes = 3,
returnMode = (SFRM_ValuePerCall | unknown: 256), isDone =
ExprSingleResult, setResult = 0x0, setDesc = 0x0}
(gdb)

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Esteban Zimanyi (#3)
Re: Error when defining a set returning function

Esteban Zimanyi <ezimanyi@ulb.ac.be> writes:

When debugging the function with gdb, I noticed that the rsinfo variable of
the PostgreSQL function ExecMakeFunctionResultSet is modified in the
macro SRF_RETURN_NEXT causing the problem. Any idea how to solve this?

Well, what SRF_RETURN_NEXT thinks it's doing is

rsi->isDone = ExprMultipleResult; \

which surely shouldn't change the returnMode field. At this point
I'm guessing that you are compiling the PG headers with some compiler
pragma that changes the struct packing rules. Don't do that.

regards, tom lane

#5Esteban Zimanyi
ezimanyi@ulb.ac.be
In reply to: Tom Lane (#4)
Re: Error when defining a set returning function

Many thanks Tom for your help !

I removed the flag -fshort-enums and everything works fine !

On Fri, Apr 16, 2021 at 7:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Show quoted text

Esteban Zimanyi <ezimanyi@ulb.ac.be> writes:

When debugging the function with gdb, I noticed that the rsinfo variable

of

the PostgreSQL function ExecMakeFunctionResultSet is modified in the
macro SRF_RETURN_NEXT causing the problem. Any idea how to solve this?

Well, what SRF_RETURN_NEXT thinks it's doing is

rsi->isDone = ExprMultipleResult; \

which surely shouldn't change the returnMode field. At this point
I'm guessing that you are compiling the PG headers with some compiler
pragma that changes the struct packing rules. Don't do that.

regards, tom lane

#6Andrew Dunstan
andrew@dunslane.net
In reply to: Esteban Zimanyi (#5)
Re: Error when defining a set returning function

On 4/16/21 3:32 PM, Esteban Zimanyi wrote:

Many thanks Tom for your help ! 

I removed the flag -fshort-enums and everything works fine !

If you build with pgxs it should supply the appropriate compiler flags.
Alternatively, get the right settings from pg_config. In general rolling
your own is a bad idea.

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

#7Esteban Zimanyi
ezimanyi@ulb.ac.be
In reply to: Andrew Dunstan (#6)
Re: Error when defining a set returning function

If you build with pgxs it should supply the appropriate compiler flags.
Alternatively, get the right settings from pg_config. In general rolling
your own is a bad idea.

I didn't know about pgxs. Many thanks Andrew for pointing this out.