postgresql - Postgres Cast 复合类型

标签 postgresql types casting composite

在 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/

相关文章:

sql - Postgresql:是否需要在作为复合唯一约束一部分的列上定义单列索引?

c - 为什么这个显式转换的结果与隐式转换的结果不同?

c++ - 有哪些对二进制打包结构消息进行版本控制的好方法?

c# - 我在哪里可以找到合适的领域?

haskell - 功能队列类型

c - 与引用变量类型不同的指针

arrays - 将 Pytorch 的张量元素转换为 "float"类型而不是 "double"

sql - 我如何请求 Postgres 获取特定时间序列中不同日期的计数?

postgresql - 如何使用外连接删除行

database - Symfony2/Doctrine 和 PostgreSQL NOTIFY/LISTEN