triggers - sqlite3 触发器将十六进制文本转换为等效的二进制 blob

标签 triggers sqlite hex blob

我想要一个插入后触发器将十六进制文本字符串转换为其等效的二进制 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

最佳答案

使用用户定义的函数会更容易且便宜得多,但我找到了解决方案。

首先,您需要一个查找表,如下所示:

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;

另外两个触发器可在数据插入或 t_hex 更新时触发 data_h_update_trigger:

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)字节。

关于triggers - sqlite3 触发器将十六进制文本转换为等效的二进制 blob,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20133602/

相关文章:

mysql - 如果我们将表导出到另一个数据库中,那么它的所有触发器也会随之导出吗?

wpf - 展开时修改展开器标题子项

c++ - QByteArray 的十六进制值如何在不转换为 ASCII 字符的情况下显示

sql - MySQL 触发器问题

sql - 从 sqlite 数据库中选择不同的一对值

javascript - Jquery从sqlite数据库获取西类牙口音时显示�符号

c# - 如何在 C# 或 VB.NET 中使用 SqLite 连接池?

具有十进制、八进制和十六进制数字的计算器

Python - 如何将 int 转换为表示 32 位十六进制数的字符串

mysql - Django 代码或 MySQL 触发器