PostgreSQL 两个-table 约束无法正常工作

PostgreSQL two-table constaint not working properly

我运行下面的代码:

-- Table describing messages
CREATE TABLE messages
(
 id serial PRIMARY KEY NOT NULL,
 text TEXT  -- Message can have or not have text
);

-- Table describing media attached to messages
CREATE TABLE messages_attachments
(
 message_id integer NOT NULL REFERENCES messages,
 -- Messages can have any number of attachments, including 0
 attachment_id TEXT NOT NULL
);

-- Messages must have either text or at least one attachment
CREATE FUNCTION message_has_text_or_attachments(integer) RETURNS bool STABLE
AS
$$
 SELECT
  EXISTS(SELECT 1 FROM messages_attachments WHERE message_id = )
 OR
  (SELECT text IS NOT NULL FROM messages WHERE id = );
$$ LANGUAGE SQL;

ALTER TABLE messages ADD CONSTRAINT nonempty_message CHECK ( message_has_text_or_attachments(id) );

-- Insert a message with no text and no attachments. Should fail, but it does not
INSERT INTO messages(text) VALUES (NULL);

SELECT *, message_has_text_or_attachments(id) FROM messages;

我预计它会在 INSERT 行失败,因为插入的行违反了检查约束(我们正在插入一条文本为 NULL 的消息,并且该消息没有附件) , 但它 运行s 成功并且下一个查询 returns (1, NULL, false)(这里是一个稍微修改过的 example函数定义(由于数据库版本的原因,使用撇号而不是美元符号)。

一件更有趣的事情是,如果我在添加 CONSTRAINT 之前更改命令的顺序和 INSERT 行,那么 PostgreSQL 将无法 ALTER table, 因为“check constraint "nonempty_message" is violated by some row”.

为什么 PostgreSQL 允许插入违反约束的行?我在函数定义的某处弄错了吗?对于如何应用约束以及它们可以依赖哪些 table 是否有一些限制?是 PostgreSQL 错误吗?

来自the docs

PostgreSQL does not support CHECK constraints that reference table data other than the new or updated row being checked. While a CHECK constraint that violates this rule may appear to work in simple tests, it cannot guarantee that the database will not reach a state in which the constraint condition is false (due to subsequent changes of the other row(s) involved).