Search Postgresql Archives

Unstable C Function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm running PG 9.5 on Win 10 64-bit. I'm compiling C under VS 2016.

I am forming a function that will evolve into a somewhat complex beast. To test out my initial efforts, the function accepts an array of int4 (this works fine and the code for processing it is not shown here). The function then grabs a few rows from a table, pushes the values into a FIFO, then pulls them out and renders the results. This approach is strategic to how the function will operate when complete.

The function works fine on first call, sometimes more, then either resets the connection or throws this on any further calls:

ERROR: cache lookup failed for type 0 SQL state: XX000

I noticed that removing references to the FIFO improves stability, but doesn't solve it. Here is my code as lean as I can get it for question purposes:

PG:

CREATE TABLE md_key
(
  id    serial NOT NULL PRIMARY KEY,
  pid   int4 NOT NULL,
  key   integer NOT NULL,
  vals  int4[]
);


CREATE OR REPLACE FUNCTION md_key_query(int4[])
  RETURNS TABLE (
    id int4,
    vals int4[]) AS E'\RoctPG', --abreviated for question
    'md_key_query'
  LANGUAGE c IMMUTABLE STRICT;


select * from md_key_query(array[1,2,3,4]::int4[])

C:

    PG_FUNCTION_INFO_V1(md_key_query);

    typedef struct
    {
        Datum              id;
        Datum              vals;
    } MdKeyNode;

    typedef struct fifoAry
    {
        MdKeyNode           nodes[32];
        struct fifoAry     *next;
        int32               readpos;
        int32               writepos;
    } FifoAry;

    typedef struct
    {
        FifoAry            *fifo;
        FifoAry            *tail;
        FifoAry            *head;
        uint32              nodescount;
        Datum              *retvals[2];
        bool               *retnulls[2];
    } CtxArgs;

    inline void push(CtxArgs *args, Datum id, Datum vals)
    {
        if (args->head->writepos == 32)
            args->head = args->head->next = (FifoAry*)palloc0(sizeof(FifoAry));

        MdKeyNode          *node = &(args->head->nodes[args->head->writepos++]);
        node->id = id;
        node->vals = vals;
        args->nodescount++;
    }


inline MdKeyNode* pop(CtxArgs *args)
{
//  if (!args->nodescount)
//      return NULL;
    if (args->tail->readpos == 32)
        args->tail = args->tail->next;

    args->nodescount--;

    return &(args->tail->nodes[args->tail->readpos++]);
}

// use STRICT in the caller wrapper to ensure a null isn't passed in
PGMODULEEXPORT Datum md_key_query(PG_FUNCTION_ARGS)
{
    uint32              i;
    FuncCallContext    *funcctx;
    HeapTuple           tuple;
    MdKeyNode          *node;
    CtxArgs            *args;

    if (SRF_IS_FIRSTCALL())
    {
        funcctx = SRF_FIRSTCALL_INIT();

        MemoryContext   oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        ArrayType      *a = PG_GETARG_ARRAYTYPE_P(0);
        Datum          *in_datums;
        bool           *in_nulls;
        bool            fieldNull;
        SPITupleTable  *tuptable = SPI_tuptable;
        int32           ret;
        uint32          proc;

        if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));

        deconstruct_array(a, INT4OID, 4, true, 'i', &in_datums, &in_nulls, &ret);

        if (!ret)
            PG_RETURN_NULL();

        (SPI_connect();

        // initialize and set the cross-call structure
        funcctx->user_fctx = args = (CtxArgs*)palloc0(sizeof(CtxArgs));
        args->fifo = args->tail = args->head = (FifoAry*)palloc0(sizeof(FifoAry));
        args->retvals = (Datum*)palloc(sizeof(Datum) * 2);
        args->retnulls = (bool*)palloc0(sizeof(bool) * 2);

        BlessTupleDesc(funcctx->tuple_desc);

// do some work here

        // this is simply a test to see if this function is behaving as expected
        ret = SPI_execute("select id, vals from public.md_key where vals is not null limit 64", true, 0);

        if (ret <= 0)
            ereport(ERROR, (errcode(ERRCODE_SQL_ROUTINE_EXCEPTION), errmsg("could not execute SQL")));

        proc = SPI_processed;

        if (proc > 0)
        {
            TupleDesc       tupdesc = SPI_tuptable->tupdesc;
            SPITupleTable  *tuptable = SPI_tuptable;

            for (i = 0; i < proc; i++)
            {
                tuple = tuptable->vals[i];
                push(args, SPI_getbinval(tuple, tupdesc, 1, &fieldNull), SPI_getbinval(tuple, tupdesc, 2, &fieldNull));
            }
        }

        SPI_finish();
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    args = funcctx->user_fctx;

    if (args->nodescount > 0)
    {
        node = pop(args);
        args->retvals[0] = node->id;
        args->retvals[1] = node->vals;
        tuple = heap_form_tuple(funcctx->tuple_desc, args->retvals, args->retnulls);
        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
    }
    else
    {
        SRF_RETURN_DONE(funcctx);
    }
}

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux