【问题标题】:AFTER INSERT OR UPDATE trigger violates not-null constantAFTER INSERT OR UPDATE 触发器违反非空常量
【发布时间】:2016-02-19 12:40:52
【问题描述】:

在文字游戏 SQLite 数据库中,我想以明文存储简短的单词和带有很少Q 字母的单词(以便能够在应用程序中列出它们)。

否则我只想存储一个单词的 MD5 哈希值(这样应用程序数据库就不会被轻易窃取)。

在后端我使用 PostgreSQL 9.5 并准备了存储函数:

CREATE OR REPLACE FUNCTION hash_word(in_word varchar(255))
        RETURNS varchar(32) AS
$func$
        SELECT CASE WHEN LENGTH(in_word) > 3 AND in_word !~ 'Q'
        THEN UPPER(MD5(in_word)) ELSE in_word END
$func$ LANGUAGE sql IMMUTABLE;

这似乎工作正常:

# SELECT hash_word('ABC');
 hash_word
-----------
 ABC
(1 row)

# SELECT hash_word('ABCDE');
            hash_word
----------------------------------
 2ECDDE3959051D913F61B14579EA136D
(1 row)

# SELECT hash_word('SQUAD');
 hash_word
-----------
 SQUAD
(1 row)

然后我创建一个表来存储大写英文单词及其散列值和 INSERT OR UPDATE 触发器:

CREATE OR REPLACE FUNCTION english_nouns_trigger()
        RETURNS TRIGGER AS
$func$
BEGIN
        DELETE FROM english_nouns WHERE word = NEW.word;

        INSERT INTO english_nouns(word, hashed)
        VALUES (NEW.word, hash_word(new.word));

        RETURN NEW;
END
$func$ LANGUAGE plpgsql;

DROP table IF EXISTS english_nouns;
CREATE TABLE english_nouns (
        word varchar(255) PRIMARY KEY CHECK (word ~ '^[A-Z]{2,}$' AND
                word !~ 'JQ' AND
                word !~ 'QG' AND
                word !~ 'QK' AND
                word !~ 'QY' AND -- impossible english bigrams
                word !~ 'QZ' AND
                word !~ 'WQ' AND
                word !~ 'WZ'),
        hashed varchar(32) NOT NULL
);

CREATE TRIGGER english_nouns_trigger
AFTER INSERT OR UPDATE ON english_nouns
FOR EACH ROW EXECUTE PROCEDURE english_nouns_trigger();

不幸的是,当我尝试插入测试值时,我得到了错误:

# INSERT INTO english_nouns (word) VALUES ('ABC'), ('ABCDE'), ('SQUAD');

ERROR:  null value in column "hashed" violates not-null constraint
DETAIL:  Failing row contains (ABC, null).

更新:

当我按照 Richard 的建议将 AFTER 更改为 BEFORE 时(谢谢!)-

CREATE TRIGGER english_nouns_trigger
BEFORE INSERT OR UPDATE ON english_nouns
FOR EACH ROW EXECUTE PROCEDURE english_nouns_trigger();

然后我不幸又遇到了另一个错误:

# INSERT INTO english_nouns (word) VALUES ('ABC'), ('ABCDE'), ('QI');

ERROR:  stack depth limit exceeded
HINT:  Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.
CONTEXT:  SQL statement "DELETE FROM english_nouns
        WHERE word = NEW.word"
PL/pgSQL function english_nouns_trigger() line 3 at SQL statement
SQL statement "INSERT INTO english_nouns(word, hashed) 
        VALUES (NEW.word, hash_word(new.word))"
PL/pgSQL function english_nouns_trigger() line 6 at SQL statement
SQL statement "INSERT INTO english_nouns(word, hashed) 
        VALUES (NEW.word, hash_word(new.word))"

【问题讨论】:

    标签: postgresql stored-procedures triggers sql-insert postgresql-9.5


    【解决方案1】:

    您想在插入数据之前更改数据吗?使用前触发器,而不是后触发器。

    【讨论】:

      【解决方案2】:

      您的表格中有 2 行:

      word varchar(255) 
      hashed varchar(32) NOT NULL
      

      您只是为 word 插入一个值。所以基本上你真正插入的是:

      INSERT INTO english_nouns (word, hashed) VALUES ('ABC', NULL), ('ABCDE', NULL), ('SQUAD', NULL);
      

      不为散列值插入带有 NOT NULL 限制的值会引发该错误。

      您需要为散列值插入一些值:

      INSERT INTO english_nouns (word, hashed) VALUES ('ABC', somevalue), ('ABCDE', somevalue), ('SQUAD', somevalue);
      

      【讨论】:

        【解决方案3】:

        好的,下面的BEFORE 触发器似乎可以工作:

        CREATE OR REPLACE FUNCTION hash_word(in_word varchar(255))
                RETURNS varchar(32) AS
        $func$
                SELECT CASE WHEN LENGTH(in_word) > 3 AND in_word !~ 'Q' 
                THEN UPPER( MD5(in_word) ) ELSE in_word END
        $func$ LANGUAGE sql IMMUTABLE;
        
        
        CREATE OR REPLACE FUNCTION english_nouns_trigger()
                RETURNS TRIGGER AS
        $func$
        BEGIN
                NEW.hashed := hash_word(NEW.word);
        
                RETURN NEW;
        END
        $func$ LANGUAGE plpgsql;
        
        
        DROP table IF EXISTS english_nouns;
        CREATE TABLE english_nouns (
                word varchar(255) PRIMARY KEY CHECK (word ~ '^[A-Z]{2,}$' AND
                        word !~ 'JQ' AND 
                        word !~ 'QG' AND 
                        word !~ 'QK' AND 
                        word !~ 'QY' AND 
                        word !~ 'QZ' AND 
                        word !~ 'WQ' AND 
                        word !~ 'WZ'),
                hashed varchar(32) NOT NULL
        );
        
        CREATE TRIGGER english_nouns_trigger 
        BEFORE INSERT OR UPDATE ON english_nouns
        FOR EACH ROW EXECUTE PROCEDURE english_nouns_trigger();
        

        演示INSERT

        # INSERT INTO english_nouns (word) VALUES ('ABC'), ('ABCDE'), ('QI');
        INSERT 0 3
        
        # TABLE english_nouns;
         word  |              hashed              
        -------+----------------------------------
         ABC   | ABC
         ABCDE | 2ECDDE3959051D913F61B14579EA136D
         QI    | QI
        (3 rows)
        

        演示UPDATE

        # UPDATE english_nouns SET word = 'ABCDEF' WHERE word = 'ABCDE';
        UPDATE 1
        
        # TABLE english_nouns;
          word  |              hashed              
        --------+----------------------------------
         ABC    | ABC
         QI     | QI
         ABCDEF | 8827A41122A5028B9808C7BF84B9FCF6
        (3 rows)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-04
          • 1970-01-01
          • 1970-01-01
          • 2013-03-29
          • 2017-04-10
          • 2023-03-18
          相关资源
          最近更新 更多