2012-01-04 1 views
2

V1 호출 규칙을 사용하여 PG 용 C 확장 라이브러리를 작성했습니다. 집계 함수를 호출하면 postgres 서버 프로세스가 충돌합니다. gdb를 사용하여 서버 프로세스를 디버그하고 Seg-V가 발생한 위치에 배치했습니다.외부 C 라이브러리에 구현 된 PostgreSQL 집계 함수

잘못된 주소에 액세스하려고했기 때문에 발생합니다. 내가 이해하지 못하는 것은 메모리가 이전에 성공적으로 할당되었다는 것입니다. 코드의 주석으로 판단 하건데, 아직 사용중인 메모리는 수확/출시되고있는 것으로 판단됩니다. 나는 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

더 문제가되어야합니다 - 잘못 등록, 반환 된 데이터의 잘못된 형식, 반환 된 데이터의 잘못된 메모리 컨텍스트 - 좋은 후두둑 당신은 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입니다에서 찾을 수 있습니다 - 당신은 이전 버전이있는 경우, 관련 소스 코드를 찾습니다.

+0

내 백엔드 db가 8.4라는 사실을 잊어 버렸습니다. 이전 버전의 PG에서 사용되는 코드. 8.4에 대한 관련 문서 링크를 게시 할 수 있습니까? 링크를 제공 한 의사가 9.1을 참조하지 않습니다. 8.4 코드에 사용할 수 있습니까? –

+0

http://archives.postgresql.org/pgsql-committers/2008-11/msg00159.php http://anoncvs.postgresql.org/cvsweb.cgi/pgsql/src/backend/utils/adt/array_userfuncs.c? r1 = 1.23 & r2 = 1.24 이것은 8.4 패치입니다. –