rowid如何确定sqlite插入?

问题描述 投票:0回答:2

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

其他一些方案?

未指定?

sqlite
2个回答
2
投票

https://sqlite.org/autoinc.html -

SQLite是单线程,所以在大多数情况下它执行select max(id) +1 from the_table。从这个角度来看,很难说出序列是什么。但是,您可以提供有效的序列威胁删除的东西,因为不存在。或许我错过了一些东西。

Edit

正如CL发现的那样。 Autoincrement以更稳定的方式工作。所以你不能两次得到相同的id。从中可以看出,同时删除了某些内容......


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.Insert出现了一个104的rowid。
  • 由于SQLite可能根据id选择第一行,然后我将id从2更改为1(1是更改为不存在的表名称的那个)为20. 3是rouge / 2nd entry行的rowid。插入的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

© www.soinside.com 2019 - 2024. All rights reserved.