2016-09-19 66 views
0

我在Win 10 64位上運行PG 9.5。我在VS 2016編譯C。不穩定的Postgresql C函數

我正在形成一個功能,將演變成一個有點複雜的野獸。爲了測試我最初的努力,函數接受一個int4數組(這工作正常,處理它的代碼在這裏沒有顯示)。然後該函數從表格中抓取幾行,將值壓入FIFO中,然後將其拉出並呈現結果。這種方法對完成後功能的運作具有戰略意義。

該功能適用​​於第一次調用罰款,然後拋出此有關的任何其他呼叫:

ERROR: cache lookup failed for type 0 SQL state: 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

的誤差可能是C函數本身內,如內存管理在[這個線程](https://www.postgresql.org/message-id/017101c4f4e7%24be262490% 240b00a8c0%40llord) – pozs

+0

'E'\ RoctPG','md_key_query''你確定'E'\ R'不被解釋爲''\ r''嗎? – joop

+0

我縮短了這部分的問題。該查詢首次執行正常。 – IamIC

回答

0

固定它。移動一個命令如下所示:

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

     SRF_RETURN_DONE(funcctx); 
}