插入或更新后触发器违反非空常量
AFTER INSERT OR UPDATE trigger violates not-null constant
在一个文字游戏 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)
然后我创建一个 table 来存储大写英文单词及其散列值和 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))"
您想在插入数据之前更改数据吗?使用前触发器,而不是后触发器。
您的 table 中有 2 行:
word varchar(255)
hashed varchar(32) NOT NULL
您只是为单词插入一个值。所以基本上你真正插入的是:
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);
好的,下面的 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();
示范[=14=]:
# 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)
示范[=15=]:
# UPDATE english_nouns SET word = 'ABCDEF' WHERE word = 'ABCDE';
UPDATE 1
# TABLE english_nouns;
word | hashed
--------+----------------------------------
ABC | ABC
QI | QI
ABCDEF | 8827A41122A5028B9808C7BF84B9FCF6
(3 rows)
在一个文字游戏 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)
然后我创建一个 table 来存储大写英文单词及其散列值和 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))"
您想在插入数据之前更改数据吗?使用前触发器,而不是后触发器。
您的 table 中有 2 行:
word varchar(255)
hashed varchar(32) NOT NULL
您只是为单词插入一个值。所以基本上你真正插入的是:
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);
好的,下面的 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();
示范[=14=]:
# 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)
示范[=15=]:
# UPDATE english_nouns SET word = 'ABCDEF' WHERE word = 'ABCDE';
UPDATE 1
# TABLE english_nouns;
word | hashed
--------+----------------------------------
ABC | ABC
QI | QI
ABCDEF | 8827A41122A5028B9808C7BF84B9FCF6
(3 rows)