整数类型的输入语法无效:执行函数时具有复合数据类型的“(2,2)”

Posted

技术标签:

【中文标题】整数类型的输入语法无效:执行函数时具有复合数据类型的“(2,2)”【英文标题】:Invalid input syntax for type integer: "(2,2)" with composite data type while executing function 【发布时间】:2022-01-07 00:01:41 【问题描述】:
begin;
create type public.ltree as (a int, b int);
create  table public.parent_tree(parent_id int,l_tree ltree);
insert into public.parent_tree values(1,(2,2)),(2,(1,2)),(3, (1,28));
commit;

试图在这个答案中复制解决方案:

Format specifier for integer variables in format() for EXECUTE?

对于复合类型的函数:

CREATE OR REPLACE FUNCTION public.get_parent_ltree
            (_parent_id int, tbl_name regclass , OUT _l_tree ltree)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format('SELECT l_tree FROM %s WHERE parent_id = $1', tbl_name)
   INTO  _l_tree
   USING _parent_id;
END
$func$;

执行的有效查询:

select l_tree from parent_tree where parent_id = 1;

执行函数:

select get_parent_ltree(1,'parent_tree');
select get_parent_ltree(1,'public.parent_tree');

我收到此错误

ERROR:  invalid input syntax for type integer: "(2,2)"  
CONTEXT:  PL/pgSQL function get_parent_ltree(integer,regclass) line 3 at EXECUTE

第 3 行的上下文:

【问题讨论】:

【参考方案1】:

它看起来像 Postgres 错误,但 Erwin 在旁边的答案中澄清了这个问题。自然的解决方法之一是以如下方式使用辅助文本变量:

create or replace function get_parent_ltree(_parent_id int, tbl_name regclass)
returns ltree language plpgsql as
$func$
declare
    rslt text;
begin
    execute format('select l_tree from %s where parent_id = $1', tbl_name)
    into rslt
    using _parent_id;
    return rslt::ltree;
end
$func$;

【讨论】:

好像和PL/pgSQL有关。没有动态 SQL 的 return query select ... 会导致相同的错误。但是,language sql 函数(显然没有动态 SQL)可以工作。 @a_horse_with_no_name:我想我的回答可以解释。【参考方案2】:

输出参数_l_tree 是一个“行变量”。 (复合类型被视为行变量。)SELECT INTO 一个接一个地分配行变量的字段。 The manual:

可选的target 是记录变量、行变量或简单变量和记录/行字段的逗号分隔列表,[... ]

因此,目前(第 14 页),行或记录变量必须独立为 target。或者正如相应的 Postgres 错误消息所说:

ERROR:  record variable cannot be part of multiple-item INTO list

这行得通:

CREATE OR REPLACE FUNCTION public.get_parent_ltree (IN  _parent_id int
                                                  , IN  _tbl_name  regclass
                                                  , OUT _l_tree    ltree)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format('SELECT (l_tree).* FROM %s WHERE parent_id = $1', _tbl_name)
   INTO  _l_tree
   USING _parent_id;
END
$func$;

或者这个:

CREATE OR REPLACE FUNCTION public.get_parent_ltree2 (IN  _parent_id int
                                                   , IN  _tbl_name  regclass
                                                   , OUT _l_tree    ltree)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format('SELECT (l_tree).a, (l_tree).b FROM %s WHERE parent_id = $1', _tbl_name)
   INTO  _l_tree.a, _l_tree.b
   USING _parent_id;
END
$func$;

db小提琴here

我同意这是相当棘手的。人们可能期望复合字段被视为单个字段(如简单类型)。但目前在 PL/pgSQL 分配中并非如此。

来自the manual about composite types的相关引用:

复合类型表示行或记录的结构;它是 本质上只是一个字段名称及其数据类型的列表。 PostgreSQL 允许以与使用简单类型相同的许多方式使用复合类型

我的大胆强调。很多。不是全部

相关:

Use of custom return types in a FOR loop in plpgsql PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"

旁白:考虑additional module ltree 而不是“发展自己的”。如果您继续使用自己的复合类型,请考虑使用不同的名称以避免与该模块混淆/冲突。

【讨论】:

我知道我为什么远离行类型 ;) @a_horse_with_no_name:我不反对。经过一段磨难和磨难之后,我可以处理它们。但我宁愿尽可能坚持简单的类型。无论如何,这就是我对初学者的建议。 感谢您的澄清。我对这个异常一无所知,对此感到矛盾。我很高兴这种行为被记录在案,但我仍然不禁觉得这是一个被掩盖的缺点。在这种情况下,用户收到的错误消息很奇怪(委婉地说)。 @klin:是的,这是 PL/pgSQL 小镇的一条黑暗小巷。更令人困惑的是,带有RETURN QUERY 的集合返回函数采用了相反的方法:dbfiddle here 一切都有原因,但结果令人困惑。 甚至:dbfiddle here

以上是关于整数类型的输入语法无效:执行函数时具有复合数据类型的“(2,2)”的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#复合数据类型–Object类型

为啥我会收到“元素类型无效:需要字符串(对于内置组件)或类/函数(对于复合组件)......”?

元素类型无效:应为字符串或类/函数(用于复合组件)但得到:对象

PB函数大全

如何修复元素类型无效:期望字符串(用于内置组件)或类/函数(用于复合组件)但得到:对象

元素类型无效:需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:未定义的 React