Postgresql Postgres铸造复合型

Postgresql Postgres铸造复合型,postgresql,types,casting,composite,Postgresql,Types,Casting,Composite,在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 implic

在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;
函数向量_来自_文本,如下所示:

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字符串(如“{”x“:0,“y“:0,“z“:0}”)或构造函数表达式(如“(0,0,0)”)

问题是:

对于类似json的输入,函数返回错误

invalid input syntax for type double precision: "(0,0,0)"
select语句将行包含到结果中时。如果我删除这一行或将输出变量从result更改为text类型,则函数将按预期工作

为什么不可能将一个已经转换为类型的向量值分配到向量中?不明白

您不需要(事实上也不应该)根据文本创建强制转换。创建复合类型时,可以将文本强制转换为该类型,而无需执行任何其他步骤:

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类型。从文本创建自定义的隐式强制转换尤其不合理。阅读:

明智的做法是保守地将强制转换标记为隐式。过多的隐式转换路径可能会导致PostgreSQL选择令人惊讶的命令解释,或者根本无法解析命令,因为存在多种可能的解释。一个好的经验法则是,使强制转换仅在同一常规类型类别中的类型之间保存信息的转换时隐式调用。例如,从int2到int4的转换可以合理地隐式进行,但从float8到int4的转换可能只应该是赋值。交叉类型的类别转换(如text-to-int4)最好只显式进行

您不需要(事实上也不应该)根据文本创建强制转换。创建复合类型时,可以将文本强制转换为该类型,而无需执行任何其他步骤:

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类型。从文本创建自定义的隐式强制转换尤其不合理。阅读:

明智的做法是保守地将强制转换标记为隐式。过多的隐式转换路径可能会导致PostgreSQL选择令人惊讶的命令解释,或者根本无法解析命令,因为存在多种可能的解释。一个好的经验法则是,使强制转换仅在同一常规类型类别中的类型之间保存信息的转换时隐式调用。例如,从int2到int4的转换可以合理地隐式进行,但从float8到int4的转换可能只应该是赋值。交叉类型的类别转换(如text-to-int4)最好只显式进行