在 postgresql 函数中选择自定义类型时出现格式错误的数组文字
Malformed array literal when selecting into custom type within a postgresql function
我有一个 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;
此函数按预期工作,returns route_part
复合类型。
我正在尝试在另一个 "wrapper" 函数中使用它,它看起来像这样:
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;
我在 select 查询中遇到错误。
ERROR: malformed array literal: "(
{303513543,2289605239,...,306687989}","
{2585314,264212,...,1088633}",
0102000020110F000029000000AE47E11A81754F41C3F5280C07F25C)"
DETAIL: Array value must start with "{" or dimension information.
我不将类型转换为字符串或其他类型,所以我无法弄清楚为什么返回值被认为具有格式错误的数组。
有什么线索吗?
解决方案是分配分解值:
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
<b>SELECT INTO routerec * FROM</b> net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
END
$func$ LANGUAGE plpgsql;
由于routerec
是行类型(复合类型),SELECT
列表的列必须与行类型的列匹配。您所拥有的表格将尝试将 return 由 net.get_route_part_dist()
编辑的值(作为一个整体)放入 第一列 routerec
.
If a row or a variable list is used as target, the query's result
columns must exactly match the structure of the target as to number
and data types
Postgres 尝试将您的复合类型(或者更确切地说是它的文本表示)放入 bigint[]
,复合类型 routerec
的第一列。你引用的错误信息就是结果。
If the expression's result data type doesn't match the variable's data
type, the value will be coerced as though by an assignment cast (see
Section 10.4). If no assignment cast is known for the pair of data
types involved, the PL/pgSQL interpreter will attempt to convert the
result value textually, that is by applying the result type's output
function followed by the variable type's input function. Note that
this could result in run-time errors generated by the input function,
if the string form of the result value is not acceptable to the input function.
这在第一次使用时也可能令人困惑和上当。区别似乎是必要的,因为 INTO
允许一次分配一个 目标变量列表 。
底线是这样的:使用 INTO
分配给行/记录/复合类型时使用 SELECT * FROM ...
分解行类型。否则将整体分配给第一个目标列。
避免这些低效的形式:
就像你评论的那样:
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)
相关:
- Passing array of a composite type to stored procedure
简单的选择
简单案例的简单替代方法:直接赋值(没有 INTO
):
routerec := net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
简单赋值只允许单个目标开始。
或者直接return结果:
RETURN net.get_route_part_dist(beg_, end_, dist);
我有一个 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;
此函数按预期工作,returns route_part
复合类型。
我正在尝试在另一个 "wrapper" 函数中使用它,它看起来像这样:
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;
我在 select 查询中遇到错误。
ERROR: malformed array literal: "(
{303513543,2289605239,...,306687989}","
{2585314,264212,...,1088633}",
0102000020110F000029000000AE47E11A81754F41C3F5280C07F25C)"
DETAIL: Array value must start with "{" or dimension information.
我不将类型转换为字符串或其他类型,所以我无法弄清楚为什么返回值被认为具有格式错误的数组。 有什么线索吗?
解决方案是分配分解值:
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
<b>SELECT INTO routerec * FROM</b> net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
END
$func$ LANGUAGE plpgsql;
由于routerec
是行类型(复合类型),SELECT
列表的列必须与行类型的列匹配。您所拥有的表格将尝试将 return 由 net.get_route_part_dist()
编辑的值(作为一个整体)放入 第一列 routerec
.
If a row or a variable list is used as target, the query's result columns must exactly match the structure of the target as to number and data types
Postgres 尝试将您的复合类型(或者更确切地说是它的文本表示)放入 bigint[]
,复合类型 routerec
的第一列。你引用的错误信息就是结果。
If the expression's result data type doesn't match the variable's data type, the value will be coerced as though by an assignment cast (see Section 10.4). If no assignment cast is known for the pair of data types involved, the PL/pgSQL interpreter will attempt to convert the result value textually, that is by applying the result type's output function followed by the variable type's input function. Note that this could result in run-time errors generated by the input function, if the string form of the result value is not acceptable to the input function.
这在第一次使用时也可能令人困惑和上当。区别似乎是必要的,因为 INTO
允许一次分配一个 目标变量列表 。
底线是这样的:使用 INTO
分配给行/记录/复合类型时使用 SELECT * FROM ...
分解行类型。否则将整体分配给第一个目标列。
避免这些低效的形式:
就像你评论的那样:
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)
相关:
- Passing array of a composite type to stored procedure
简单的选择
简单案例的简单替代方法:直接赋值(没有 INTO
):
routerec := net.get_route_part_dist(beg_, end_, dist);
RETURN routerec;
简单赋值只允许单个目标开始。
或者直接return结果:
RETURN net.get_route_part_dist(beg_, end_, dist);