布尔值插入PostgreSQL中的字符变化字段

时间:2015-01-29 15:37:30

标签: postgresql

PostgreSQL 9.1很乐意将一个布尔值插入到varchar字段中。我的期望是,这会失败,因为我正在插入错误类型的数据,我希望在我的应用程序逻辑中调出错误。除了为每个varchar字段创建触发器或约束之外,还有什么方法可以将其设置为默认行为吗?

CREATE TABLE
foo
(
    text_field CHARACTER VARYING(32)
);

这两个都将'false'插入text_field:

INSERT INTO foo (text_field) VALUES (FALSE);
INSERT INTO foo (text_field) VALUES (CAST('f' AS BOOLEAN));

2 个答案:

答案 0 :(得分:1)

这种情况会发生,因为PostgreSQL会接受任何表达式(在INSERT语句中),其类型可以自动转换为该列的类型(更准确地说,这两种类型之间存在ASSIGNMENT or IMPLICIT强制转换:这就是为什么这些演员阵容首先存在的原因)。 F.ex:

-- lets see what casts exists to boolean & text
-- "castcontext" is 'a' for ASSIGNMENT, 'i' for IMPLICIT and 'e' for EXPLICIT casts
select castsource::regtype::text,
       casttarget::regtype::text,
       castcontext
from   pg_cast
where  casttarget in ('boolean'::regtype, 'text'::regtype);

create table foo (
  varchar_field varchar,
  text_field    text,
  bool_field    boolean
);

-- these are equivalents, because of some casts
insert into foo values ('false', 'false', 'false');
insert into foo values (false, false, false);
-- this will throw an error
insert into foo values (0, 0, 0);

好的,我有点作弊。有一个特例。当您编写字符串文字(如'false')时,它具有unknown类型。未知值始终传递给实际列类型input function。真text类型的文字看起来有点不同:text 'false'。如果再次查看PostgreSQL提供的默认强制转换,您可以看到没有从textboolean的强制转换。这就是最后一句话失败的原因:

insert into foo values (text 'false', text 'false', text 'false');

SQLFiddle

修改:默认情况下,从ASSIGNMENTboolean会有text强制转换(&还有一个character varying )。这就是你的表text_field接受布尔输入的原因。

答案 1 :(得分:1)

  

我的期望是这会失败,因为我插入了错误类型的数据。 。

SQL语句通常涉及混合数据类型。 SQL引擎(不仅仅是PostgreSQL)遵循内部规则,将一种类型的值静默转换为另一种类型的值。 PostgreSQL的规则记录在Type Conversion中。插入值的规则是Value Storage

虽然可能可以改变pg_cast系统目录的内容(我不知道),但我认为真的 坏了理念。首先,pg_cast不会被pg_dump备份。灾难恢复可能很容易使dbms处于您不期望的状态,并且很难进行故障排除。

我认为最好的办法是停止将布尔值插入到不应出现的列中。严重的是,为什么是应用程序代码,例如设置类似" city& #34;为假?

您的下一个最佳选择是添加CHECK约束。

alter table foo
add constraint disallow_tf_text_field
check (lower(text_field) not in ('t', 'f', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off', '1', '0'));