gpt4 book ai didi

c - 在外部 C 库中实现的 PostgreSQL 聚合函数(崩溃服务器)

转载 作者:太空宇宙 更新时间:2023-11-03 23:55:34 25 4
gpt4 key购买 nike

我已经为 PG 编写了一个 C 扩展库,使用 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

最佳答案

应该还有更多问题 - 注册错误、返回数据格式错误、返回数据内存上下文错误 - 您可以在 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 的 - 如果您有旧版本,请查看相关源代码。

关于c - 在外部 C 库中实现的 PostgreSQL 聚合函数(崩溃服务器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8730756/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com