You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 07:17:56