不稳定的Postgresql C函数

时间:2016-09-19 14:51:48

标签: sql c postgresql function postgresql-9.5

我在Win 10 64位上运行PG 9.5。我在VS 2016下编译C。

我正在形成一个将演变成有点复杂的野兽的功能。为了测试我最初的努力,该函数接受一个int4数组(这很好,并且这里没有显示处理它的代码)。然后,该函数从表中抓取几行,将值推入FIFO,然后将它们拉出并呈现结果。这种方法对于功能在完成时的运作方式具有战略意义。

该功能在第一次调用时工作正常,然后在任何进一步调用时抛出此函数:

  

错误:类型0 SQL状态:XX000

的缓存查找失败

我不知道造成这种情况的原因。

但是,有时候它不会抛出错误但会不停地执行。

这是我的代码,因为我可以将其用于问题目的:

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);
    }
}

1 个答案:

答案 0 :(得分:0)

修正了它。移动了一个命令,如下所示:

{
        // function is unstable if this is put earlier
        SPI_finish();

        SRF_RETURN_DONE(funcctx);
}