我有一个postgresql自定义类型,包含数组
CREATE TYPE route_part (
nodea bigint[],
edgea bigint[],
geom geometry
);
一个函数,返回这个类型
CREATE OR REPLACE FUNCTION net.get_route_part_dist(int8, int8, int4)
RETURNS route_part
AS
$BODY$
DECLARE routerec route_part;
BEGIN
SELECT INTO routerec
...
;
RETURN routerec;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
此函数按预期工作并返回route_part
复合类型。
我试图在另一个“包装”函数中使用它,看起来像这样:
CREATE OR REPLACE FUNCTION net.get_route(beg_ int8, end_ int8, mida int8[], dist int4)
RETURNS route_part
AS
$BODY$
DECLARE routerec route_part;
BEGIN
SELECT INTO routerec net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
我在选择查询时遇到错误。
ERROR: malformed array literal: "(
{303513543,2289605239,...,306687989}","
{2585314,264212,...,1088633}",
0102000020110F000029000000AE47E11A81754F41C3F5280C07F25C)"
DETAIL: Array value must start with "{" or dimension information.
我没有将类型转换为字符串或其他类型,因此我无法弄清楚为什么返回值被认为具有格式错误的数组。 有线索吗?
答案 0 :(得分:0)
解决方案是分配分解值:
CREATE OR REPLACE FUNCTION net.get_route(beg_ int8, end_ int8, mida int8[], dist int4)
RETURNS route_part AS
$func$
DECLARE
routerec route_part;
BEGIN
SELECT INTO routerec * FROM net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
END
$func$ LANGUAGE plpgsql;
由于routerec
是行类型(复合类型),因此SELECT
列表的列必须与行类型的列匹配。您拥有的表单会尝试将net.get_route_part_dist()
返回的值(作为一个整体)放入routerec
的 第一列 。
如果使用行或变量列表作为目标,则查询结果 列必须与目标的结构完全匹配 和数据类型
Postgres尝试将您的复合类型(或者更确切地说是其文本表示)放入bigint[]
,即复合类型routerec
的第一列。您引用的错误消息是结果。
如果表达式的结果数据类型与变量的数据不匹配 类型,该值将被强制转换,就像通过赋值转换一样(请参阅 Section 10.4)。如果对于该对数据没有已知的赋值转换 涉及的类型,PL / pgSQL解释器将尝试转换 结果值是文本,即通过应用结果类型的输出 函数后跟变量类型的输入函数。注意 这可能导致输入函数生成运行时错误, 如果输入函数不接受结果值的字符串形式。
这也可能是第一次令人困惑和愚弄。由于INTO
允许同时分配 目标变量列表 ,因此区分似乎是必要的。
底线是:在使用SELECT * FROM ...
分配行/记录/复合类型时,使用INTO
分解行类型。否则,它将作为一个整体分配给第一个目标列。
避免 这些效率低下的形式:
像你评论的那样:
<击> SELECT INTO routerec (net.get_route_part_dist(beg_, end_, dist)).nodea
, (net.get_route_part_dist(beg_, end_, dist)).edgea
, (net.get_route_part_dist(beg_, end_, dist)).geom;
击>
或者,更简洁,但同样效率低下:
<击> SELECT INTO routerec (net.get_route_part_dist(beg_, end_, dist)).*;
击>
每个人都会多次评估这个功能 - 而不是:
SELECT INTO routerec * FROM net.get_route_part_dist(beg_, end_, dist)
相关:
简单案例的简单替代方案:直接分配(不含INTO
):
routerec := net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
简单分配只允许单个目标开始。
或直接返回结果:
RETURN net.get_route_part_dist(beg_, end_, dist);