在 Postgres 9.6 中使用函数转换为复合类型时,我遇到了一个奇怪的行为。
我已经将复合类型“向量”声明为 x,y,z - 每个都是 double 的,并且如下所示:
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,或者两种输入格式的向量类型要么是像 '{"x":0, "y":0, "z":0}' 这样的 json 字符串,要么是像这样的构造函数表达式'(0,0,0)'。
问题:
对于json-like 输入,函数返回错误
invalid input syntax for type double precision: "(0,0,0)"
一旦选择语句包含 into result 行。如果我删除此行或将输出变量从 result 更改为 text 类型,函数将按预期工作。
为什么不能将一个已经类型化的vector 转换值分配给一个vector?不明白!
最佳答案
您不需要(事实上不应该)从文本创建一个转换。当您创建复合类型时,您可以将文本转换为该类型,而无需任何额外步骤:
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: :
It is wise to be conservative about marking casts as implicit. An overabundance of implicit casting paths can cause PostgreSQL to choose surprising interpretations of commands, or to be unable to resolve commands at all because there are multiple possible interpretations. A good rule of thumb is to make a cast implicitly invokable only for information-preserving transformations between types in the same general type category. For example, the cast from int2 to int4 can reasonably be implicit, but the cast from float8 to int4 should probably be assignment-only. Cross-type-category casts, such as text to int4, are best made explicit-only.
关于postgresql - Postgres Cast 复合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47077277/