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));
答案 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提供的默认强制转换,您可以看到没有从text
到boolean
的强制转换。这就是最后一句话失败的原因:
insert into foo values (text 'false', text 'false', text 'false');
修改:默认情况下,从ASSIGNMENT
到boolean
会有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'));