修改create_vlabel函数接收name[]参数后调用报错:函数不存在
问题描述
我修改了ag_catalog.create_vlabel函数,将参数从2个调整为3个:
- 原函数定义(在age--1.2.0.sql中):
CREATE FUNCTION ag_catalog.create_vlabel(graph_name name, label_name name) RETURNS void LANGUAGE c AS 'MODULE_PATHNAME';
- 修改后的函数定义:
CREATE FUNCTION ag_catalog.create_vlabel(graph_name name, label_name name, parent_list name[]) RETURNS void LANGUAGE c AS 'MODULE_PATHNAME';
接着我在label_commands.c文件中修改了函数实现,新增第三个参数的处理逻辑:如果参数不为空,就遍历数组将父标签添加到List *parent中,实现标签继承,核心代码如下:
// [...] // 新增变量 ArrayType *list_parents; Datum *elements_parent_names; Name parent_name; char *parent_name_str; int num_parents; // [...] // 创建默认标签表 graph = graph_name->data; label = label_name->data; rv = get_label_range_var(graph, graph_oid, AG_DEFAULT_LABEL_VERTEX); parent = list_make1(rv); // 检查用户是否传入父标签列表 if (!PG_ARGISNULL(2)) { // 获取第三个参数的数组内容 list_parents = PG_GETARG_ARRAYTYPE_P(2); num_parents = ArrayGetNItems(ARR_NDIM(list_parents), ARR_DIMS(list_parents)); elements_parent_names = (Datum *) ARR_DATA_PTR(list_parents); // 遍历每个父标签 for (int i = 0; i < num_parents; i++) { parent_name = DatumGetName(elements_parent_names[i]); parent_name_str = NameStr(*parent_name); // 检查父标签是否存在 if (!label_exists(parent_name_str, graph_oid)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("parent label \"%s\" does not exist.", parent_name_str))); } rv = get_label_range_var(graph, graph_oid, parent_name->data); lappend(parent, rv); } } create_label(graph, label, LABEL_TYPE_VERTEX, parent);
测试时,不传第三个参数可以正常执行:
-- 执行成功 SELECT * FROM ag_catalog.create_vlabel('demo', 'Book'); NOTICE: VLabel "Book" has been created create_vlabel --------------- (1 row)
但传入数组参数时触发错误:
-- 报错 SELECT * FROM ag_catalog.create_vlabel('demo', 'Fantasy', ARRAY['Book']); ERROR: function ag_catalog.create_vlabel(unknown, unknown, text[]) does not exist LINE 1: SELECT * FROM ag_catalog.create_vlabel('demo', 'Fantasy', ARRAY... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
请问如何修复该问题,使函数能正常接收并处理传入的数组参数?
解决方案
错误原因是:调用时传入的ARRAY['Book']属于text[]类型,但函数定义的第三个参数是name[]类型,PostgreSQL无法自动完成这种类型转换,因此找不到匹配的函数。
有两种可行修复方式:
方式1:调用时显式转换数组类型
在调用语句中把text[]数组强制转换为name[]类型:
SELECT * FROM ag_catalog.create_vlabel('demo', 'Fantasy', ARRAY['Book']::name[]);
方式2:修改函数定义兼容text[]类型
如果希望用户调用时无需手动转换,可以调整函数参数类型并修改C代码逻辑:
- 更新SQL函数定义:
CREATE FUNCTION ag_catalog.create_vlabel(graph_name name, label_name name, parent_list text[]) RETURNS void LANGUAGE c AS 'MODULE_PATHNAME';
- 修改C代码中的参数处理逻辑,将
text类型元素转换为Name类型:
// 遍历父标签的循环中修改 for (int i = 0; i < num_parents; i++) { // 获取text类型的父标签名并转为字符串 text *parent_text = DatumGetTextPP(elements_parent_names[i]); parent_name_str = text_to_cstring(parent_text); // 转换为Name类型 parent_name = makeString(parent_name_str); // 后续检查与添加逻辑保持不变 if (!label_exists(parent_name_str, graph_oid)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("parent label \"%s\" does not exist.", parent_name_str))); } rv = get_label_range_var(graph, graph_oid, parent_name_str); lappend(parent, rv); }
额外建议:保留原有的2参数版本函数,避免破坏原有代码兼容性:
CREATE FUNCTION ag_catalog.create_vlabel(graph_name name, label_name name) RETURNS void LANGUAGE c AS 'MODULE_PATHNAME';
内容的提问来源于stack exchange,提问作者Matheus Farias
相关产品推荐
相关产品推荐

