我想预测(真正反向工程)sqlite表中任何要插入的行的rowid(使用某些表的rowid作为其他表中的外键重建sqlite插入流)。插入可以在任意插入和删除序列之后发生。如何在插入时由sqlite确定rowid?
这是一个不断递增的反击吗?
int64_t next_rowid() {
static int64_t r = 0;
return ++r;
}
也许最小的一行未使用?
// Algorithm description, not (likely) working code
static sorted_set<int64_t> deleted;
static int64_t top = 0;
int64_t next_rowid() {
if(deleted.size()==0) deleted.push(++top);
return deleted.pop_front();
}
void delete_rowid(int64_t r) {
deleted.push(r);
}
其他一些方案?
未指定?
答案 0 :(得分:2)
https://sqlite.org/autoinc.html -
SQLite是单线程,因此对于大多数情况,它执行select max(id) +1 from the_table
。从这个角度来看,很难说出序列是什么。但是,您可以提供有效的序列威胁删除的东西,因为不存在。或许我错过了一些东西。
CL发现。 Autoincrement
以更稳定的方式运作。所以你不能两次得到相同的id。从中可以看出,同时删除了某些内容......
答案 1 :(得分:0)
首先,有两种类型的rowid确定算法。取决于是否已指定AUTOINCREMENT
。
AUTOINCREMENT
表示rowid可以保证在数字大小限制内增加(9223372036854775807)。如果达到该数字,则任何后续插入尝试都将失败,并出现SQLITE_FULL异常。
在上述场景中没有AUTOINCREMENT
,算法将尝试查找未使用的rowid,因此结果rowid可能低于其他现有rowid。
两种算法都不保证增量为1,而通常它们会增加1。
AUTOINCREMENT
导致创建表 sqlite_sequence ,最后使用的rowid保存在序列列中,注意!它可以被操纵/改变,所以添加1个记录然后将其更改为100,下一个插入可能是101.
name列是该行所用表的名称。
我将名称列作为测试更改为不存在的表名(最后一个序列是101),插入一条仍然产生102的记录,因此在没有相应序列的情况下会出现在sqlite_sequence中,算法仍然找到一个更高的rowid。
然后我将序列降低到2,下一个rowid是103。
所以保证更高的rowid似乎是彻底的。
我接下来为序列号为600的同一个表的sqlite_sequence添加了第二行。插入后出现了一个104的rowid。
由于SQLite可能会根据id选择第一行,然后我将id从2更改为1(1是已更改为不存在的表名称的那个)为20. 3是该行的rowid胭脂/第2行。插入的rowid是601.
作为试图欺骗SQLite的尝试,我删除了表中新添加的行和sidite_sequence表中rowid为3,序列值为601的行。 SQLite被愚弄了,插入行的rowid是105。
因此,算法似乎与以下几行有关: -
a)未指定AUTOINCREMENT
的地方
b)1大于插入行的表中最高rowid的大小,以及sqlite_sequence表中表的第一行中存储的序列。注意到sqlite_sequence表可以被更新,但是然后插入不会发生,例如如果插入因约束而失败。