更新/插入之前的触发仅在大约 99.9% 的时间内工作,而此前是 100% 可靠地工作

问题描述 投票:0回答:1

在我组织的一个数据库中,有一张表

customerReview
。 简化后,它看起来像:

CREATE TABLE customerReview(
    customerReviewId SERIAL PRIMARY KEY,
    dateTimeCreated  TIMESTAMP WITHOUT TIME ZONE,
    dateTimeUpdated  TIMESTAMP WITHOUT TIME ZONE,
    businessID       INTEGER,
    reviewText       TEXT,
    reviewerIP       TEXT,
    isIPv6           BOOLEAN
)

我没有创建表,但我添加了

isIPv6
列和触发器函数:

CREATE OR REPLACE FUNCTION review_ip_version()
    RETURNS TRIGGER AS
$BDY$
    IF NEW.reviewerip ~ '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' THEN
        NEW.isIPv6 := FALSE;
    ELSIF NEW.reviewerip ~ '^[0-9a-f]{0,4}(:[0-9a-f]{0,4}){2,7}$' 
        AND NEW.reviewerip !~ '::.*::|:::|[0-9a-f]{5,}|(:[0-9a-f]*){7}:' THEN 
        NEW.isIPv6 := TRUE
    END IF;

    RETURN NEW;
END;
$BDY$
LANGUAGE 'plpgsql';

目的是当

isIPv6
匹配有效的 IPv6 模式时
reviewerip
为 true,当它匹配有效的 IPv4 模式时为 false,否则为 null。 经过测试,它可以在包括 NULL 在内的各种模式下准确执行。

调用该函数的触发器是

BEFORE INSERT OR UPDATE
。 在添加触发器之前,在同一事务中,我使用相同的正则表达式更新了所有现有行以具有正确的
isIPv6
值。 这只是说我确信
isIPv6
列值在创建触发器后看起来与应有的样子完全一样。第二天测试也成功了。

触发器工作了大约一个月,没有任何问题,但就在今天,有些东西停止工作了。 具体来说,我们有 7 行失败。 所有 7 行都有

reviewerip = NULL
。 6 行有
isIPv6 = FALSE
,而 1 行有
isIPv6 = TRUE
(值应为 NULL)。 我知道它今天停止工作了,因为其他地方依赖于
isIPv6
正确的流程刚刚中断。 触发器仍然存在并且适用于绝大多数行。

我的工作假设是某些进程正在更新值,但没有启动触发器。 不幸的是,我的组织没有保留日志表,并且

dateTimeUpdated
并不可靠,因为它不是在数据库级别强制执行的,而是通过某些 Web 进程强制执行的。 所以我没有什么可做的了。 但是是否存在一些模糊的情况,更新可以绕过表上的
BEFORE INSERT OR UPDATE
触发器?

postgresql triggers
1个回答
0
投票

您的触发函数存在语法错误:缺少首字母

BEGIN
和分号。

修复这些错误后,情况对我来说似乎很清楚:如果我用

reviewerip
的值更新一行,而该行与任一模式都不匹配(如 NULL),则
NEW.isIPv6
不会更改,因此它只保留它所具有的值更新之前。

您必须改进触发器功能,例如通过添加将列设置为 NULL 的

ELSE
分支。

© www.soinside.com 2019 - 2024. All rights reserved.