如何在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';
错误原因
- 类型不匹配:函数声明返回
integer[][](对应PostgreSQL的int4[][]类型),但C代码中使用INT8OID(bigint类型)构建子数组,外层数组使用INT8ARRAYOID,导致PostgreSQL无法识别错误的类型OID,触发缓存查找失败。 - 内存泄漏:用
palloc分配的row_values未释放,会造成PostgreSQL内存泄漏。 - 对齐标志与参数不匹配:部分
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
相关产品推荐
相关产品推荐

