Агрегатная функция PostgreSQL, реализованная во внешней библиотеке C (сбой сервера) - PullRequest
2 голосов
/ 04 января 2012

Я написал библиотеку расширения C для PG, используя соглашение о вызовах V1.Когда я вызываю агрегатную функцию, происходит сбой процесса на сервере postgres.Я использовал gdb для отладки серверного процесса и обнаружил, где происходит Seg-V.

Это вызвано попыткой доступа к неверному адресу.что я не понимаю, так это то, что память была успешно распределена ранее.Судя по комментарию в коде, я подозреваю, что память собирается / освобождается, пока она еще используется.Я не знаю достаточно о внутренностях postgres - но это кажется вероятной причиной проблемы.

Я включил код для функции, которая вызывает сбой, и выделил строку, которая вызывает Seg-V,Я вызываю MemoryContextAlloc с правильными параметрами?

static PGARRAY *GetPGArray(int4 state, int fAdd);    
static PGARRAY *ShrinkPGArray(PGARRAY * p);

Datum       float8_agg_state(PG_FUNCTION_ARGS);    
Datum       float8_agg_final_count(PG_FUNCTION_ARGS);    
Datum       float8_agg_final_array(PG_FUNCTION_ARGS);    
Datum       float8_enum(PG_FUNCTION_ARGS);        

PG_FUNCTION_INFO_V1(float8_agg_state);    
PG_FUNCTION_INFO_V1(float8_agg_final_count);    
PG_FUNCTION_INFO_V1(float8_agg_final_array);    
PG_FUNCTION_INFO_V1(float8_enum);

/*    
 * Manage the aggregation state of the array    
 *    
 * Need to specify a suitably long-lived memory context, or it will vanish!    
 * PortalContext isn't really right, but it's close enough (famous last words ...).    
 */

static PGARRAY *    
GetPGArray(int4 state, int fAdd)    
{    
    PGARRAY    *p = (PGARRAY *) state;

    if (!state)    
    {    
        /* New array */    
        int cb = PGARRAY_SIZE(START_NUM);       

        p = (PGARRAY *) MemoryContextAlloc(PortalContext, cb);    
        p->a.vl_len_ = cb;    
        p->a.ndim = 0;    
        p->a.dataoffset = 0;

#ifndef PG_7_2    
        p->a.elemtype = FLOAT8OID;    
#endif

        p->items = 0;    
        p->lower = START_NUM; 
    }
    else if (fAdd)    
    {       
           /* Ensure array has space */

           /* SEG-V fault on the line below */
        if (p->items >= p->lower)    
        {    
            PGARRAY *pn;    
            int n = p->lower + p->lower;   
            int cbNew = PGARRAY_SIZE(n);

            pn = (PGARRAY *) repalloc(p, cbNew);    
            pn->a.vl_len_ = cbNew;    
            pn->lower = n;    
            return pn;   
        }    
    }

    return p;    
}

Может кто-нибудь определить, почему код SG-V?

[[Редактировать]]

Мой внутренний PG-сервер v8.4.9

1 Ответ

1 голос
/ 04 января 2012

должно быть больше проблем - неправильная регистрация, неправильный формат возвращаемых данных, неправильный контекст памяти возвращаемых данных - хороший шаблон, который можно найти в реализации array_agg http://doxygen.postgresql.org/array__userfuncs_8c_source.html

00477 array_agg_transfn(PG_FUNCTION_ARGS)
00478 {
00479     Oid         arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
00480     MemoryContext aggcontext;
00481     ArrayBuildState *state;
00482     Datum       elem;
00483 
00484     if (arg1_typeid == InvalidOid)
00485         ereport(ERROR,
00486                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00487                  errmsg("could not determine input data type")));
00488 
00489     if (!AggCheckCallContext(fcinfo, &aggcontext))
00490     {
00491         /* cannot be called directly because of internal-type argument */
00492         elog(ERROR, "array_agg_transfn called in non-aggregate context");
00493     }
00494 
00495     state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
00496     elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
00497     state = accumArrayResult(state,
00498                              elem,
00499                              PG_ARGISNULL(1),
00500                              arg1_typeid,
00501                              aggcontext);
00502 
00503     /*
00504      * The transition type for array_agg() is declared to be "internal", which
00505      * is a pass-by-value type the same size as a pointer.  So we can safely
00506      * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
00507      */
00508     PG_RETURN_POINTER(state);
00509 }

Это для 9.1если у вас более старая версия, посмотрите соответствующий исходный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...