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

如何在PostgreSQL的C函数中返回动态创建的矩阵(Apache AGE场景)

PostgreSQL扩展返回邻接矩阵的类型缓存错误解决

问题描述

在为Apache AGE开发PostgreSQL扩展函数时,生成邻接矩阵后尝试返回时触发错误:

ERROR: cache lookup failed for type 2139062143

函数声明为返回integer[][],但C代码中使用int64类型构建数组,核心代码及函数声明如下:

原矩阵初始化代码

// Allocate memory for adjacency matrix.
adjacency_matrix = (int64**)malloc(vertex_count * sizeof(int64*));
for (i = 0; i < vertex_count; i++)
{
    adjacency_matrix[i] = (int64*)malloc(vertex_count * sizeof(int64));
}

// Fill the matrix with zeros.
for (i = 0; i < vertex_count; i++)
{
    for (j = 0; j < vertex_count; j++)
    {
        adjacency_matrix[i][j] = 0;
    }
}

原返回逻辑代码

// Create a PostgreSQL array of arrays to hold the matrix.
Datum *row_arrays = (Datum *) palloc(sizeof(Datum) * vertex_count);

// Populate the array of arrays with sub-arrays (rows).
for (i = 0; i < vertex_count; i++)
{
    Datum *row_values = (Datum *) palloc(sizeof(Datum) * vertex_count);
    for (j = 0; j < vertex_count; j++)
    {
        row_values[j] = Int64GetDatum(adjacency_matrix[i][j]);
    }

    // Construct a 1D array for each row and store it in the array of arrays.
    row_arrays[i] = PointerGetDatum(construct_array(
        row_values,
        vertex_count,
        INT8OID,
        sizeof(int64),
        true,
        'd'
    ));
}

// Construct the final array of arrays (2D array)
matrix_array = construct_array(
    row_arrays,
    vertex_count,
    INT8ARRAYOID,
    sizeof(Datum),
    false,
    'd'
);

SPI_finish();

// Free allocated memory for adjacency matrix.
for (i = 0; i < vertex_count; i++)
{
    free(adjacency_matrix[i]);
}

free(adjacency_matrix);

PG_RETURN_ARRAYTYPE_P(matrix_array);

原函数声明

CREATE FUNCTION ag_catalog.get_adjacency_matrix(graph_name name)
RETURNS integer[][]
LANGUAGE c
AS 'MODULE_PATHNAME';

错误原因

  1. 类型不匹配:函数声明返回integer[][](对应PostgreSQL的int4[][]类型),但C代码中使用INT8OID(bigint类型)构建子数组,外层数组使用INT8ARRAYOID,导致PostgreSQL无法识别错误的类型OID,触发缓存查找失败。
  2. 内存泄漏:用palloc分配的row_values未释放,会造成PostgreSQL内存泄漏。
  3. 对齐标志与参数不匹配:部分construct_array参数未严格对应目标类型的要求。

修正方案

方案1:保持函数返回integer[][](推荐)

将C代码中的数据类型统一为int32(对应PostgreSQL的integer),调整construct_array的参数:

// 调整adjacency_matrix为int32**类型(或转换现有int64值为int32)
int32** adjacency_matrix;

// ... 矩阵初始化逻辑(将原int64改为int32) ...

// Create a PostgreSQL array of arrays to hold the matrix.
Datum *row_arrays = (Datum *) palloc(sizeof(Datum) * vertex_count);

for (i = 0; i < vertex_count; i++)
{
    Datum *row_values = (Datum *) palloc(sizeof(Datum) * vertex_count);
    for (j = 0; j < vertex_count; j++)
    {
        // 转换为int32,匹配integer类型
        row_values[j] = Int32GetDatum((int32)adjacency_matrix[i][j]);
    }

    // 构建int4类型的一维数组
    ArrayType *row_array = construct_array(
        row_values,
        vertex_count,
        INT4OID,          // integer类型的OID
        sizeof(int32),    // int32的字节数
        false,            // 无NULL元素,设为false
        'i'               // int4的对齐标志
    );
    row_arrays[i] = PointerGetDatum(row_array);
    
    // 释放临时分配的row_values
    pfree(row_values);
}

// 构建二维数组(元素为int4[])
ArrayType *matrix_array = construct_array(
    row_arrays,
    vertex_count,
    INT4ARRAYOID,       // int4[]类型的OID
    sizeof(Datum),
    false,              // 无NULL子数组
    'd'                 // Datum的对齐标志
);

// 释放row_arrays
pfree(row_arrays);

SPI_finish();

// 释放矩阵内存
for (i = 0; i < vertex_count; i++)
{
    free(adjacency_matrix[i]);
}
free(adjacency_matrix);

PG_RETURN_ARRAYTYPE_P(matrix_array);

方案2:修改函数返回bigint[][]

如果需要保留int64类型,修改函数声明为:

CREATE FUNCTION ag_catalog.get_adjacency_matrix(graph_name name)
RETURNS bigint[][]
LANGUAGE c
AS 'MODULE_PATHNAME';

C代码中保持INT8OID和INT8ARRAYOID,并确保对齐标志为'd',同时释放临时内存:

// ... 矩阵初始化逻辑(保持int64**) ...

for (i = 0; i < vertex_count; i++)
{
    Datum *row_values = (Datum *) palloc(sizeof(Datum) * vertex_count);
    for (j = 0; j < vertex_count; j++)
    {
        row_values[j] = Int64GetDatum(adjacency_matrix[i][j]);
    }

    ArrayType *row_array = construct_array(
        row_values,
        vertex_count,
        INT8OID,
        sizeof(int64),
        false,
        'd'
    );
    row_arrays[i] = PointerGetDatum(row_array);
    
    pfree(row_values);
}

ArrayType *matrix_array = construct_array(
    row_arrays,
    vertex_count,
    INT8ARRAYOID,
    sizeof(Datum),
    false,
    'd'
);

pfree(row_arrays);

// ... 后续释放与返回逻辑 ...

关键注意事项

  • 类型一致性:必须保证函数声明的返回类型与C代码中使用的OID完全匹配,integer对应INT4OID/INT4ARRAYOID,bigint对应INT8OID/INT8ARRAYOID。
  • 内存管理:用palloc分配的临时内存(如row_values、row_arrays)必须用pfree释放,construct_array返回的ArrayType由PostgreSQL自动管理。
  • 对齐标志:typalign参数必须匹配类型的对齐要求,int4为'i',int8和Datum为'd'。

内容的提问来源于stack exchange,提问作者Matheus Farias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 02:56:02