rowid如何确定sqlite插入?

时间:2017-12-21 21:46:44

标签: sqlite

我想预测(真正反向工程)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);
}

其他一些方案?

未指定?

2 个答案:

答案 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的地方

    • 1大于插入行的表中的最高rowid,除非它大于9223372036854775807,在这种情况下将寻找未使用的rowid。
  • b)1大于插入行的表中最高rowid的大小,以及sqlite_sequence表中表的第一行中存储的序列。注意到sqlite_sequence表可以被更新,但是然后插入不会发生,例如如果插入因约束而失败。

Much of the above is based upon this