首页 > 解决方案 > 与 UPDATE 规则相比,postgres INSERT 规则中生成的 UUID 行为

问题描述

我有一个带有单个表的 postgres 数据库。该表的主键是生成的 UUID。我正在尝试向该数据库添加一个日志记录表,以便每当添加或删除一行时,日志记录表都会获得一个条目。我的表具有以下结构

CREATE TABLE configuration (
     id    uuid NOT NULL DEFAULT uuid_generate_v4(),
     name  text,
     data  json 
);

我的日志记录表具有以下结构

CREATE TABLE configuration_log (
    configuration_id         uuid,
    new_configuration_data   json,
    old_configuration_data   json,
    "user"                   text,
    time                     timestamp
);

我添加了以下规则:

CREATE OR REPLACE RULE log_configuration_insert AS ON INSERT TO "configuration"
       DO INSERT INTO configuration_log VALUES (
          NEW.id,
          NEW.data,
          '{}',
          current_user,
          current_timestamp
       );

CREATE OR REPLACE RULE log_configuration_update AS ON UPDATE TO "configuration"
      WHERE NEW.data::json::text != OLD.data::json::text
      DO INSERT INTO configuration_log VALUES (
          NEW.id,
          NEW.data,
          OLD.data,
          current_user,
          current_timestamp
      );

现在,如果我在配置表中插入一个值,那么配置表中的 UUID 和 configuration_log 表中的 UUID 是不同的。例如,插入查询

INSERT INTO configuration (name, data) 
       VALUES ('test', '{"property1":"value1"}')

结果是这样...... UUIDc2b6ca9b-1771-404d-baae-ae2ec69785ac在配置表中,而在 configuration_log 表中结果是...... UUID id16109caa-dddc-4959-8054-0b9df6417406

但是,更新规则按预期工作。因此,如果我将更新查询编写为

UPDATE "configuration" 
    SET "data" = '{"property1":"abcd"}' 
    WHERE "id" = 'c2b6ca9b-1771-404d-baae-ae2ec69785ac';

configuration_log 表获得正确的 UUID,如此处所示c2b6ca9b-1771-404d-baae-ae2ec69785ac

NEW.id在这两个规则中都使用了,所以我期待相同的行为。谁能指出我在这里可能做错了什么?

谢谢

标签: postgresqluuidrules

解决方案


这是另一个很好的例子,为什么应该避免规则

从手册中引用

对于对 NEW 的任何引用,将在原始查询的目标列表中搜索相应的条目。如果找到,该条目的表达式将替换引用

所以NEW.id被替换为uuid_generate_v4()解释为什么你看到不同的值。

您应该将其重写为触发器。


顺便说一句: usingjsonb优先于json,那么您还可以摆脱列的(基本上不正确的)演员表jsontext比较内容。


推荐阅读