PostgreSQL自定义聚合返回ArrayType报错:type arraytype is only a shell求助
问题排查:PostgreSQL自定义聚合返回数组时出现"type arraytype is only a shell"错误
错误核心原因
你遇到的问题根源是SQL函数定义的返回类型写错了:ArrayType是PostgreSQL内部C代码中的结构体名称,并非SQL层面的合法数据类型。PostgreSQL的SQL类型体系里不存在名为ArrayType的类型,因此数据库会将其识别为未定义的"shell类型",触发报错。
解决方案步骤
1. 修正SQL函数的返回类型
将finalize_trans_crimes_c函数的返回类型从ArrayType改为SQL层面的具体数组类型,比如你要返回bigint数组,就写bigint[]。
2. 清理C代码中的冗余操作
你的C代码里先通过palloc0(nbytes)分配了result指针,随后又用construct_array覆盖了该指针,这行分配属于冗余操作,会造成内存泄漏,直接删除即可。
修改后的代码示例
修正后的SQL代码
CREATE FUNCTION res_trans_crimes_c(bytea, bigint) RETURNS bytea AS 'MODULE_PATHNAME', 'res_trans_crimes_c' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE FUNCTION finalize_trans_crimes_c(bytea) -- 替换ArrayType为具体的SQL数组类型bigint[] RETURNS bigint[] AS 'MODULE_PATHNAME','finalize_trans_crimes_c' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE AGGREGATE reservoir_sampling_c(bigint) ( sfunc = res_trans_crimes_c, stype = bytea, FINALFUNC = finalize_trans_crimes_c, INITCOND='{}' );
优化后的C代码
PG_FUNCTION_INFO_V1(finalize_trans_crimes_c); Datum finalize_trans_crimes_c(PG_FUNCTION_ARGS) { ArrayType *result; Datum *elems; int i; int num; int64 *dr; state_c *st = palloc0 (sizeof(state_c)); bytea *addr = (bytea *) PG_GETARG_BYTEA_P(0); void **new_ptr = (void **) VARDATA(addr); st= (state_c *) (*new_ptr); num = st->reservoir_size; dr = (int64 *) ARR_DATA_PTR(st->reservoir); elems = (Datum *)palloc(num * sizeof(Datum)); for (i = 0; i < num; i++) { elems[i] = Int64GetDatum(dr[i]); elog(INFO, "dr[%d] is %ld",i,dr[i]); elog(INFO, "elems[%d] is %ld",i,elems[i]); } // 移除冗余的palloc0调用,直接用construct_array生成数组 result = construct_array((Datum *)elems, num, INT8OID, sizeof(int64), true, 'i'); PG_RETURN_ARRAYTYPE_P(result); //PG_RETURN_ARRAYTYPE_P(st->reservoir); }
额外说明
- 如果需要返回其他类型的数组,只需将SQL里的
bigint[]替换为对应类型的数组(比如integer[]、text[]),同时将C代码中的INT8OID改为对应类型的OID(比如INT4OID、TEXTOID)。 - 若直接返回
st->reservoir,需确保该数组的元素类型与SQL函数声明的返回数组类型完全一致。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

