我想要一个插入后触发器,将十六进制文本字符串转换为二进制blob等效字符。
我尝试过这样的事情:
CREATE TABLE data
(
t_hex TEXT,
b_hex BLOB
);
CREATE TRIGGER data_insert_trigger AFTER INSERT ON data
BEGIN
UPDATE data SET b_hex = "x''"||t_hex||"''" WHERE rowid = new.rowid;
END;
INSERT into data(t_hex) VALUES ('A5A5');
这导致:
sqlite> select * from data;
t_hex = A5A5
b_hex = x''A5A5''
也尝试了
CREATE TRIGGER data_insert_trigger AFTER INSERT ON data
BEGIN
UPDATE data SET b_hex = x''||t_hex||'' WHERE rowid = new.rowid;
END;
这导致:
sqlite> select * from data;
t_hex = A5A5
b_hex = A5A5
任何人都知道如何利用x'value'语法引用现有列值或者某些其他基于SQL的机制?
** 编辑 * *
考虑到自定义功能,感谢CL和LS_dev。对于LS_dev提供的SQL唯一解决方案,这里是我所在的位置。我将data_t_update_trigger调整为
CREATE TRIGGER data_t_update_trigger
AFTER UPDATE ON data
WHEN NEW.t_hex IS NOT OLD.t_hex
BEGIN
UPDATE data SET b_hex = x'' WHERE ROWID = NEW.ROWID;
END;
我的测试集生成了:
sqlite> insert into data(t_hex) values('A5A5');
sqlite> select t_hex, hex(b_hex) from data;
A5A5|A5A5
sqlite> update data set t_hex = 'FF';
sqlite> select t_hex, hex(b_hex) from data;
FF|FF
sqlite> update data set t_hex = 'FFFE';
sqlite> select t_hex, hex(b_hex) from data;
FFFE|FFFE3F
sqlite> update data set t_hex = '00';
Error: too many levels of trigger recursion
通过我将data_h_update_trigger中的几行限定为:
CREATE TRIGGER data_b_update_trigger
AFTER UPDATE ON data
WHEN LENGTH(NEW.t_hex)>LENGTH(NEW.b_hex)*2
BEGIN
UPDATE data SET b_hex = NEW.b_hex||COALESCE((
SELECT b FROM _hb WHERE h=SUBSTR(NEW.t_hex, (LENGTH(NEW.b_hex)*2)+1, 2)
), CAST('?' AS BLOB)) WHERE ROWID = NEW.ROWID;
END;
现在我的测试集产生了:
sqlite> select t_hex, hex(b_hex) from data;
A5A5|A5A5
sqlite> update data set t_hex = 'FF';
sqlite> select t_hex, hex(b_hex) from data;
FF|FF
sqlite> update data set t_hex = 'FFFE';
sqlite> select t_hex, hex(b_hex) from data;
FFFE|FFFE
sqlite> update data set t_hex = '00';
Error: too many levels of trigger recursion
仍然处理一些无法解释的递归。 FWIW,这也发生在这样的声明中:
sqlite> update data set t_hex = 'DEADBEEF';
Error: too many levels of trigger recursion
运行: SQLite版本3.7.9 2011-11-01 00:52:41
答案 0 :(得分:0)
Blob literals只能直接在SQL语句中使用;它们不能从SQL代码动态构造。
要将十六进制字符串转换为blob,您必须安装自己的用户定义函数。
答案 1 :(得分:0)
使用用户定义的函数会更容易和便宜,但我得到了一个解决方案。
首先,您需要一个查找表:
CREATE TABLE _hb(h TEXT COLLATE NOCASE, b BLOB);
BEGIN;
INSERT INTO _hb VALUES('00', x'00');
INSERT INTO _hb VALUES('01', x'01');
(...)
INSERT INTO _hb VALUES('A4', x'A4');
INSERT INTO _hb VALUES('A5', x'A5');
INSERT INTO _hb VALUES('A6', x'A6');
(...)
INSERT INTO _hb VALUES('FE', x'FE');
INSERT INTO _hb VALUES('FF', x'FF');
COMMIT;
然后,启用recursive triggers(SQLite> = 3.6.18):
PRAGMA RECURSIVE_TRIGGERS=1;
你可以创建一个触发器,逐步将字节附加到b_hex
:
CREATE TRIGGER data_h_update_trigger
AFTER UPDATE ON data
WHEN LENGTH(NEW.t_hex)>LENGTH(NEW.b_hex)*2
BEGIN
UPDATE data SET b_hex = b_hex||COALESCE((
SELECT b FROM _hb WHERE h=SUBSTR(NEW.t_hex, LENGTH(b_hex)*2+1, 2)
), CAST('?' AS BLOB)) WHERE ROWID = NEW.ROWID;
END;
在数据插入或data_h_update_trigger
更新时触发t_hex
的另外两个触发器:
CREATE TRIGGER data_insert_trigger
AFTER INSERT ON data
BEGIN
UPDATE data SET b_hex = x'' WHERE ROWID = NEW.ROWID;
END;
CREATE TRIGGER data_t_update_trigger
AFTER UPDATE OF t_hex ON data
BEGIN
UPDATE data SET b_hex = x'' WHERE ROWID = NEW.ROWID;
END;
限制:单步blob计算限制为SQLITE_MAX_TRIGGER_DEPTH
(默认为1000)字节。