Thread: Error when defining a set returning function

Error when defining a set returning function

From
Esteban Zimanyi
Date:
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


Re: Error when defining a set returning function

From
Tom Lane
Date:
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



Re: Error when defining a set returning function

From
Esteban Zimanyi
Date:
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)

Re: Error when defining a set returning function

From
Tom Lane
Date:
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



Re: Error when defining a set returning function

From
Esteban Zimanyi
Date:
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:
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

Re: Error when defining a set returning function

From
Andrew Dunstan
Date:
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




Re: Error when defining a set returning function

From
Esteban Zimanyi
Date:

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.