В sqlite3 требуется ли сброс после неудачного обращения к шагу? - PullRequest
0 голосов
/ 25 февраля 2019

Требуется ли вызывать 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;
   }

Обратите внимание, что если вызов пошаговый не выполнен, я не делаю сброс.Ничто в документации или результатах поиска в Google не указывает на то, что sqlite3_reset() необходимо вызывать при сбоях.Фактически, документация гласит, что вызов sqlite3_reset() после сбоя также будет неудачным:

Если самый последний вызов sqlite3_step (S) для подготовленного оператора S указалошибка, то sqlite3_reset (S) возвращает соответствующий код ошибки.

Чтение этого заставило меня подумать, что, возможно, мне не следует вызывать функцию сброса, если шаг не пройден.

Может кто-нибудь уточнить?Обратите внимание, что в моем случае sqlite3_step() не работает из-за SQLITE_BUSY.Я использую режим журналирования WAL.Как только шаг завершается для подготовленного оператора, этот оператор всегда находится в состоянии занятости, когда я звоню sqlite3_step().Вызов sqlite3_bind_*() после этого возврата sqlite3_bind_int64() failed (21): bad parameter or other API misuse (формат журнала мой, но 21 - код ошибки), что заставляет меня думать, что сброс должен вызываться в случаях сбоя, так как все ошибки кажутсяозначает, что база данных занята из-за того, что подготовленный оператор застрял в середине транзакции из-за отсутствия сброса.

1 Ответ

0 голосов
/ 25 февраля 2019

Обратите внимание, что если вызов пошаговый не выполнен, я не делаю сброс.Ничто в документации или результатах поиска в Google не указывает на то, что sqlite3_reset() должен вызываться при сбоях.

Ну нет, не конкретно , а документы для sqlite3_reset() скажи

Функция sqlite3_reset () вызывается для сброса подготовленного объекта оператора обратно в его первоначальное состояние, готовое к повторному выполнению.

Вы добавляете,

Фактически, в документации говорится, что вызов sqlite3_reset() после сбоя также завершится неудачей:

Если самый последний вызов sqlite3_step (S) дляподготовленный оператор S указывает на ошибку, затем sqlite3_reset (S) возвращает соответствующий код ошибки.

Нет, вы неверно истолковываете это.Существует важное различие между «возвращает соответствующий код ошибки» и «потерпит неудачу».Это должно быть понятнее, если рассматривать его в контексте этого отрывка из документов для sqlite3_step():

В устаревшем интерфейсе API sqlite3_step () всегда возвращает общую ошибкукод SQLITE_ERROR, после любой ошибки, кроме SQLITE_BUSY и SQLITE_MISUSE.Вы должны вызвать sqlite3_reset () или sqlite3_finalize (), чтобы найти один из конкретных кодов ошибок, который лучше описывает ошибку.

Хотя такое поведение sqlite3_step() применяется только к устаревшему интерфейсу, но неИнтерфейс V2 объясняет, почему возвращаемое значение sqlite3_reset() сообщает о результате предыдущих вызовов (если таковые имеются) в sqlite3_step(), а не об его собственном успехе или неудаче.Подразумевается, что сам сброс не может завершиться неудачей или, по крайней мере, не может сообщить о своей собственной ошибке через свой код возврата.

Чтение этого заставило меня подумать, что, возможно, мне не следует вызывать функцию сброса, если шагне удается.

В документах по sqlite3_step() есть следующее:

Для всех версий SQLite до 3.6.23.1 включительно, вызовsqlite3_reset () был необходим после того, как sqlite3_step () возвратил что-либо кроме SQLITE_ROW перед любым последующим вызовом sqlite3_step ().

Примечание: следовательно, не неправильно для вызова sqlite3_reset()после sqlite3_step() сообщает об ошибке.Далее в документах говорится:

Сбой сброса подготовленного оператора с помощью sqlite3_reset () приведет к возврату SQLITE_MISUSE из sqlite3_step ().Но после версии 3.6.23.1 (2010-03-26, sqlite3_step () начал автоматически вызывать sqlite3_reset (), а не возвращать SQLITE_MISUSE.

Это кажется несовместимым с поведением, о котором вы сообщаете, но обратите вниманиечто,

[...] Параметр времени компиляции SQLITE_OMIT_AUTORESET можно использовать для восстановления устаревшего поведения.

Таким образом, ваша самая безопасная ставка - сбросить операторбезусловно, вместо того, чтобы избегать сброса его после сообщения об ошибке. Это может быть ненужным во многих сборках SQLite3, но это не является неправильным или вредным, и это необходимо в некоторых сборках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...