如何避免 PostgreSQL 中的隐式类型转换?

Joh*_*zer 6 postgresql datatypes type-conversion

我刚刚发现我可以将任何类型的值插入到 PostgreSQL (9.6) 类型的列中text

drop table if exists d cascade;
create table d ( a text );
insert into d values ( 42 );
insert into d values ( true );
select a, pg_typeof( a ) from d;

  a   | pg_typeof
------+-----------
 42   | text
 true | text
(2 rows)
Run Code Online (Sandbox Code Playgroud)

这是故意的功能吗?我做错了什么吗?有没有设置可以避免这种情况?这是否违反了 RDBMS 应该是类型安全的假设?

我知道这text在 PostgreSQL 中就像一个包罗万象的东西,这通常很方便,因为您可以编写任意类型的字符串表示。但是有时您肯定希望确保只有字符串被插入到给定的列中,以排除隐式转换值。

我能做些什么来避免“随意”类型转换?

Jac*_*las 9

  • 这是故意的功能吗?

    是的,隐式类型转换是一个有意的特性。无论哪种方式都有优点和缺点,但这就是 postgres的设计方式:

    在很多情况下,用户不需要了解类型转换机制的细节。但是,PostgreSQL 进行的隐式转换会影响查询的结果。必要时,可以使用显式类型转换来定制这些结果

  • 这是否违反了 RDBMS 应该是类型安全的假设?

    不,一切仍然是类型安全的,并且“SQL 是一种强类型语言”。隐式转换不会改变这一点。

  • 我能做些什么来避免“随意”类型转换?

    除了弄乱系统目录,这通常是一个非常糟糕的主意(在某些情况下不可能的),您可以做很多事情来完全避免隐式转换。即使您在任何地方都包含显式转换,隐式转换仍可能会错误地发生:

    create table t(foo text);
    insert into t(foo) values(11::integer);
    
    Run Code Online (Sandbox Code Playgroud)
    select * from t;
    
    Run Code Online (Sandbox Code Playgroud)
    | 富|
    | :-- |
    | 11 |
    

    dbfiddle在这里


Erw*_*ter 8

@Jack 说的话。
另外,准确地说,你的演员表在INSERT常识上是“隐式的”:

insert into d values ( 42 );
Run Code Online (Sandbox Code Playgroud)

但它是一个赋值转换,而不是Postgres 术语中的隐式转换。这是一个重要的区别,隐式强制转换有更多的应用。看:

分配隐式强制转换仅基于...

1.系统目录中的一个条目pg_cast

castcontext = 'a'castcontext = 'i'分别。

当前安装的完整列表:

SELECT casttarget::regtype AS target_type
     , castsource::regtype AS source_type
     , castcontext
FROM   pg_cast
WHERE  castcontext IN ('i', 'a')
ORDER  BY 1, 2;
Run Code Online (Sandbox Code Playgroud)

2. 附加通用规则

手册:

需要注意的是pg_cast,并不代表系统知道如何执行的每一种类型转换;只有那些不能从某些通用规则中推导出来的。例如,域与其基类型之间的转换在pg_cast. 另一个重要的例外是“自动 I/O 转换强制转换”,即使用数据类型自己的 I/O 函数在text或其他字符串类型之间进行转换而执行的转换,pg_cast.

大胆强调我的。

从理论上讲,您可以通过更改或更改为(“显式”)来弄乱pg_cast( 1. ) 中的 条目- 这可能会产生深远的影响并且是一个坏主意,除非您确切地知道自己在做什么;但不是与其余的(2.)。'i''a''e'

有关的:

演员来自 unknown

再次引用有关“常量”的手册

PostgreSQL 中有三种隐式类型的常量:字符串、位字符串和数字。常量也可以用显式类型指定,这可以使系统更准确地表示和更有效地处理。

在那一章中有更多细节。

unknown-type 文字是字符串,可以使用上面提到的“自动 I/O 转换转换”进行转换。但是 Postgres 需要在确定合适的类型转换之前确定目标类型。在普通赋值中,目标类型是显而易见的。在其他情况下,确定目标类型可能很棘手。在以下方面有广泛的规则体系: