在sqlite3中,调用步骤失败后是否需要重置?

voi*_*ter 5 c sqlite

sqlite3_reset()调用失败后是否需要调用准备好的语句sqlite3_step()?我正在使用 sqlite3 版本 3.23.1。我准备好的语句的生命周期如下:

  1. 在应用程序开始时,我全局执行sqlite3_prepare_v2()并保留准备好的语句的句柄在应用程序的生命周期内可用。
  2. 当我准备好执行查询时,我会调用其中一个sqlite3_bind_*()函数,然后执行sqlite3_step()该语句,直到得到SQLITE_ROW除返回之外的其他内容。
  3. 然后执行下面的代码来重置该语句。

这是我调用后发生的代码部分sqlite3_step()。请注意,变量resultCode保存最后一次调用的返回值sqlite3_step()

   if (resultCode == SQLITE_DONE || resultCode == SQLITE_ROW)
   {
      if (sqlite3_reset(m_statement) != SQLITE_OK)
      {
         LogDbFailure(*m_db, "sqlite3_reset()");
      }
   }
   else
   {
      LogDbFailure(*m_db, "sqlite3_step()");
      success = false;
   }
Run Code Online (Sandbox Code Playgroud)

请注意,如果对步骤的调用失败,我不会进行重置。Google 上的文档或搜索结果中没有任何内容表明sqlite3_reset()必须在失败时调用。事实上,文档指出,sqlite3_reset()失败后调用也会失败:

如果最近对准备好的语句 S 的 sqlite3_step(S) 调用指示错误,则 sqlite3_reset(S) 返回适当的错误代码。

读到这篇文章让我觉得如果步骤失败,也许我不应该调用重置函数。

谁能澄清一下吗?请注意,就我而言,sqlite3_step()失败是因为SQLITE_BUSY. 我正在使用 WAL 日志模式。一旦准备好的语句上的步骤失败,当我调用 时,该准备好的语句将永远处于繁忙状态sqlite3_step()sqlite3_bind_*()return 之后的调用sqlite3_bind_int64() failed (21): bad parameter or other API misuse(日志格式是我自己的,但 21 是错误代码),这让我认为在失败情况下应该调用重置,因为所有错误似乎都表明数据库正忙,因为准备好的语句卡住了由于缺乏重置而处于交易中期。

Joh*_*ger 6

请注意,如果对步骤的调用失败,我不会进行重置。Google 上的文档或搜索结果中没有任何内容表明 sqlite3_reset()必须在失败时调用。

嗯,不,不是具体的,但是文档确实sqlite3_reset()

调用 sqlite3_reset() 函数将准备好的语句对象重置回其初始状态,准备重新执行。

你补充说,

事实上,文档指出,sqlite3_reset()失败后调用也会失败:

如果最近对准备好的语句 S 的 sqlite3_step(S) 调用指示错误,则 sqlite3_reset(S) 返回适当的错误代码。

不,你误解了这一点。“返回适当的错误代码”和“将失败”之间有一个重要的区别。在以下文档sqlite3_step()摘录的上下文中考虑时,这一点应该会更清楚:

在旧版接口中,sqlite3_step() API 始终在 SQLITE_BUSY 和 SQLITE_MISUSE 之外的任何错误之后返回通用错误代码 SQLITE_ERROR。您必须调用 sqlite3_reset() 或 sqlite3_finalize() 才能找到更好地描述错误的特定错误代码之一。

尽管 的行为sqlite3_step()仅适用于旧接口,而不是 V2 接口,但它解释了为什么 的返回值sqlite3_reset()报告先前调用(如果有)的结果sqlite3_step(),而不是其自身的成功或失败。隐含的是重置本身不能失败,或者至少不能通过其返回代码报告其自身的失败。

读到这篇文章让我觉得如果步骤失败,也许我不应该调用重置函数。

文档对此sqlite3_step()有这样的说法:

对于 SQLite 3.6.23.1 及之前的所有版本,在 sqlite3_step() 返回除 SQLITE_ROW 以外的任何内容之后,在后续调用 sqlite3_step() 之前,需要调用 sqlite3_reset()。

注意:因此报告错误后调用并没有错。文档继续说,sqlite3_reset()sqlite3_step()

未能使用 sqlite3_reset() 重置准备好的语句将导致 sqlite3_step() 返回 SQLITE_MISUSE。但在版本3.6.23.1(2010-03-26)之后,sqlite3_step()开始在这种情况下自动调用sqlite3_reset()而不是返回SQLITE_MISUSE。

这似乎与您报告的行为不一致,但请注意,

[...] SQLITE_OMIT_AUTORESET 编译时选项可用于恢复遗留行为。

因此,最安全的选择是无条件重置语句,而不是在报告错误后避免重置它。对于许多 SQLite3 构建来说这可能是不必要的,但这并不是错误或有害的,而且对于某些构建来说这是必要的。

  • @void.pointer,所有文档引用均来自截至今天的当前文档。它们适用于您的版本。界面之所以成为现在的样子是有历史原因的,但是设计带有历史包袱并不意味着您可以期望它的行为与记录的不同。就文档允许不同行为的可能性而言,是的,我的观点是您的代码应该容纳*所有*记录的可能性。 (2认同)