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

Invalid input syntax for type integer: "(2,2)" with composite data type while executing function

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;

尝试复制此答案中的解决方案:

对于复合类型的函数:

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 = ', 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 行的上下文:

它看起来像是一个 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 = ', tbl_name)
    into rslt
    using _parent_id;
    return rslt::ltree;
end
$func$;

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

The optional target is a record variable, a row variable, or a comma-separated list of simple variables and record/row fields, [...]

因此,目前(第 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 = ', _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 = ', _tbl_name)
   INTO  _l_tree.a, _l_tree.b
   USING _parent_id;
END
$func$;

db<>fiddle here

我同意这相当棘手。人们可能希望将复合字段视为单个字段(如简单类型)。但目前在 PL/pgSQL 作业中并非如此。

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

A composite type represents the structure of a row or record; it is essentially just a list of field names and their data types. PostgreSQL allows composite types to be used in many of the same ways that simple types can be used.

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

相关:

  • PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"

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