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

时间:2019-02-25 14:33:28

标签: c sqlite

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

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

这是我调用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;
   }

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

  

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

读到这篇文章使我认为,如果步骤失败,也许我不应该调用reset函数。

任何人都可以澄清吗?请注意,在我的情况下,sqlite3_step()由于SQLITE_BUSY而失败。我正在使用WAL日记模式。一旦对准备好的语句执行步骤失败,那么当我调用sqlite3_step()时,该准备好的语句将永远处于繁忙状态。在返回sqlite3_bind_*()之后调用sqlite3_bind_int64() failed (21): bad parameter or other API misuse(日志格式是我自己的,但是错误代码是21),这让我认为在失败的情况下应该调用reset ,因为所有错误似乎都表明数据库正忙,原因是由于缺少复位而使准备好的语句滞留在事务处理中间。

1 个答案:

答案 0 :(得分:4)

  

请注意,如果对步骤的调用失败,则不会进行重置。什么都没有   Google上的文档或搜索结果表明   sqlite3_reset()必须在失败时被调用。

不,不是具体,但是the docs for sqlite3_reset()确实会说

  

调用sqlite3_reset()函数来重置准备好的语句   对象恢复到初始状态,准备重新执行。

您添加

  

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

     
    

如果对准备好的语句S的sqlite3_step(S)的最新调用指示错误,则sqlite3_reset(S)返回一个错误。     相应的错误代码。

  

不,您误解了这一点。 “返回适当的错误代码”和“将失败”之间有重要区别。在此摘录自the docs for sqlite3_step()的上下文中,应该更清楚:

  

在旧版界面中,sqlite3_step()API始终返回一个   通用错误代码SQLITE_ERROR,跟随除以下以外的任何错误   SQLITE_BUSY和SQLITE_MISUSE。您必须调用sqlite3_reset()或   sqlite3_finalize()以查找特定的错误代码之一   可以更好地描述错误。

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

  

读到这篇文章让我觉得也许我不应该给复位打个电话   如果步骤失败,则功能正常。

sqlite3_step()的文档在这一点上有这样的说法:

  

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

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

  

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

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

  

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

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