首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Imposter Tables

冒名顶替者表是与索引连接在同一个B-tree上的表格。冒名顶替者表允许查询或修改索引的内容,就像该索引是普通表一样。

Imposter表仅用于分析和调试。这不是大多数应用程序开发人员应该理解甚至了解的功能。Imposter表仅供专家使用。

冒名顶替者表的使用不当可能会导致索引损坏,尽管以这种方式创建的任何损坏都可以通过运行REINDEX来解决。

SQLite中的每个表和每个索引都存储在数据库文件的单独的b-tree中。每个B树都由其根页码来标识。通过查询sqlite_master表的“rootpage”列,可以找到任何索引或表的根页码。有关此设计的更多背景信息,请参阅索引教程和文件格式文档。

通常,表和索引的b-树略有不同。表b树包含一个64位整数密钥和任意数据。64位整数键是ROWID。索引b-tree包含一个任意的二进制密钥并且没有数据。所以表b树和索引b树不直接兼容。

但是,WITHOUT ROWID表的b-tree与索引b-tree的格式相同。因此,索引b-tree可以像访问一个WITHOUT ROWID表一样被访问。

2.1.手动创建虚构表

创建冒名顶替者表的一种方法是直接编辑sqlite_master表以插入描述该表的新行。例如,假设模式如下所示:

代码语言:javascript
复制
CREATE TABLE t1(a INTEGER PRIMARY KEY,b TEXT,c INT, d INT);
CREATE INDEX t1bc ON t1(b,c);

WITHOUT ROWID表与t1bc索引具有相同的结构,如下所示:

代码语言:javascript
复制
CREATE TABLE t2(b TEXT,c INT,a INT, PRIMARY KEY(b,c,a)) WITHOUT ROWID;

要为索引“t1bc”创建一个永久性冒名顶替者表“t2”,首先应该通过运行“PRAGMA writable_schema = ON”来启用对sqlite_master表的编辑。(小心观察这个PRAGMA附带的警告,错误会导致严重的数据库损坏。)然后在sqlite_master表中插入一个新条目,如下所示:

代码语言:javascript
复制
INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)
 SELECT 'table','t2','t2',rootpage,
   'CREATE TABLE t2(b,c,a,PRIMARY KEY(b,c,a))WITHOUT ROWID'
   FROM sqlite_master
  WHERE name='t1bc';

上面的INSERT语句在sqlite_master表中添加了一个新行,该表定义了一个表“t2”,该表具有与索引“t1bc”相同的磁盘格式并指向相同的b-tree。添加这个sqlite_master表项后,必须关闭并重新打开数据库才能让SQLite重新读取模式。然后可以查询“t2”表以查看“t1bc”索引的内容。

2.1.1.损坏的数据库

上面描述的手动冒名顶替者表方法的一个严重问题是,在向“sqlite_master”表添加新的“t2”条目之后,数据库文件在技术上将损坏。“t1bc”索引和“t2”表都将指向相同的b-tree。这不会造成任何直接问题,但应避免运行VACUUM。

可以写入“t2”表,从而改变索引的内容。但这样做会使“t1bc”索引与其父表“t1”不同步。不同步的索引可能会导致查询结果不正确。

由于“t2”冒名顶替者表是数据库损坏的一种形式,因此不推荐手动创建冒名顶替者表。实际上,除了专家开发者之外,任何对冒名顶替者表的使用都是不鼓励的,但是手动创建冒充者表是特别不鼓励的,因为它们是永久性的。

2.2.瞬态冒充者表

创建冒名顶替者表的另一种(更安全)方法是将冒名顶替者表添加到SQLite的内部符号表中,而不更新磁盘上的“sqlite_master”表。这样,冒名顶替者表只存在于单个数据库连接中,并且在重新加载模式时自动删除。

创建瞬态冒充者表涉及特殊的sqlite3_test_control()调用。与所有其他SQLite API不同,sqlite3_test_control()接口受到从一个发行版到下一个发行版的不兼容更改的影响,因此下面描述的机制不能保证在未来的SQLite版本中可用。SQLite开发人员不认为这是一个问题,因为冒充者表不应该用在应用程序中。Imposter表仅用于分析和测试。

要创建瞬态冒充者表,首先调用sqlite3_test_control(),如下所示:

代码语言:javascript
复制
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 1, tnum);

“db”参数是一个指向数据库连接的指针。“主要”参数是要在其中创建冒名顶替者表的模式的名称。“1”参数启用冒名顶替表机制。“tnum”是冒名顶替者表应该镜像的索引的根页面。

在上面的sqlite3_test_control()调用之后,然后运行CREATE TABLE语句定义了冒名顶替者表。启用冒名顶替机制后,这个CREATE TABLE语句不会创建一个真正的表,而只是在SQLite的内部符号表中添加一个条目。请注意,CREATE TABLE语句的索引格式必须正确。如果冒名顶替者表的列数不正确,或者不是WITHOUT ROWID表,或者与索引B树不兼容,则在使用冒名顶替者表时将导致SQLITE_CORRUPT错误。

运行CREATE TABLE语句后,按如下所示禁用冒名顶替机制:

代码语言:javascript
复制
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 0);

换句话说,进行相同的sqlite3_test_control()调用,除非将最后两个参数更改为零。

在如上所述将冒名顶替者表加载到SQLite的内部模式之后,冒名顶替者表可以用作任何其他表。但冒名顶替者表只对创建它的一个数据库连接可见。磁盘上的数据库文件不做任何更改。冒充者表将在下次架构加载时消失。

2.3.imposter Shell命令

从SQLite 3.16.0(2017-01-02)开始,命令行shell包含一个dot命令“.imposter”,它可以完成设置瞬态冒充者表的所有工作。除了对sqlite3_test_control()进行多次调用并找出并调用兼容的CREATE TABLE语句之外,可以按如下所示构建一个瞬态冒充者表:

代码语言:javascript
复制
.imposter t1bc t2

当然,用所需的索引和冒名顶替者表替换示例中所示的“t1bc”和“t2”。“.imposter”命令读取“t1bc”索引的模式,使用该信息为冒充者表构造兼容的CREATE TABLE语句,然后进行所有必要的调用以自动创建瞬态冒充者表。

冒名顶替者表机制是SQLite的功耗分析和调试工具。但是与所有尖锐的工具一样,它也可能是危险的,并且如果滥用会导致数据库文件损坏。不要试图在应用程序中使用冒名顶替者表。专家们打算将实验台用于实验室。

代码语言:javascript
复制
 SQLite在公共领域。

扫码关注腾讯云开发者

领取腾讯云代金券