在Postgres 9.6中使用函数转换为复合类型时,我遇到了一种奇怪的行为。
我已经将复合类型“vector”声明为x,y,z - 每个双精度以及强制转换如下:
create type vector as(
x double precision,
y double precision,
z double precision
);
create cast (text as vector)
with function vector_from_text(text) as implicit;
函数vector_from_text如下所示:
create or replace function vector_from_text(text, out result vector) strict immutable language plpgsql as $$
declare
d double precision[];
begin
result := null;
if ($1 is null) then
return;
end if;
begin
with c1 as (
select $1::jsonb src
)
select row((src->>'x')::double precision, (src->>'y')::double precision, (src->>'z')::double precision)::vector
**into result** -- see below
from c1;
exception
when others then
d := translate($1, '()', '{}')::double precision[];
result := row(d[1], d[2], d[3])::vector;
end;
end$$
;
该函数在null上返回null,或者两种输入格式的矢量类型都是json-string,如'{“x”:0,“y”:0,“z”:0}'或类似的构造函数表达式'(0,0,0)'
问题:
对于 json-like inputs ,函数返回错误
invalid input syntax for type double precision: "(0,0,0)"
一旦select语句包含到结果行。如果我删除此行或将输出变量从 result 更改为 text 类型,则函数将按预期工作。
为什么不能将已经输入 vector 的已转换值分配到向量中?不明白!
答案 0 :(得分:2)
您不需要(实际上不应该)从文本创建强制转换。创建复合类型时,可以将文本转换为该类型,而无需任何其他步骤:
create type my_record as(
x int,
y int,
z int
);
select '(1,2,3)'::my_record;
my_record
-----------
(1,2,3)
(1 row)
如果你想使用jsonb,请从jsonb创建一个强制转换为类型:
create or replace function my_record_from_jsonb(obj jsonb, out result my_record)
strict immutable language plpgsql as $$
begin
select (obj->>'x')::int, (obj->>'y')::int, (obj->>'z')::int
into result;
end
$$;
create cast (jsonb as my_record)
with function my_record_from_jsonb(jsonb);
select '{"x":1, "y":2, "z":3}'::jsonb::my_record;
my_record
-----------
(1,2,3)
(1 row)
不要试图以两种不同的方式解释文本文字。如果要使用jsonb语法,请使用jsonb类型。从文本创建自定义隐式广告特别不合理。阅读in the documentation::
保守地将标记视为隐含是明智的。过多的隐式转换路径可能会导致PostgreSQL选择令人惊讶的命令解释,或者根本无法解析命令,因为有多种可能的解释。一个好的经验法则是,只允许在同一类型类别中的类型之间保留信息的隐式调用。例如,从int2到int4的转换可以合理地隐式,但是从float8到int4的转换应该只是赋值。交叉类型转换(例如text to int4)最好只显示为。