What does HRESULT 0x87AF0065 (SQLITE_E_DONE) mean?

 
Previous Next
SQLITE_E_ROW SQLITE_E_BUSY_RECOVERY

SQLITE_E_DONE

SQLITE_E_DONE (0x87AF0065) represents sqlite3_step has completed the prepared statement. This value corresponds to SQLite result code 101. It signals successful exhaustion for a query or successful completion for a statement that returns no more rows. For SQLITE_E_DONE, apply the native SQLite state-machine rules even though Windows stores the result in an HRESULT facility.

State transition

SituationMeaning
After SQLITE_ROWDONE means there are no further result rows.
INSERT/UPDATE/DELETEDONE indicates execution completed; inspect changes only through the appropriate SQLite APIs.
Next useReset or finalize the statement before executing it again.

Do not conflate completion with commit

A statement can reach DONE inside a transaction that is later rolled back. Record transaction boundaries separately, especially when several statements form one logical operation.

Control tests

  1. Run an empty-result SELECT and verify immediate DONE
  2. Run a multi-row query and require ROW before DONE
  3. Inject a constraint failure and confirm it is not translated to DONE

Completion criterion

The caller handles DONE as a successful terminal state, performs required transaction work, and never reads column values after the row lifetime has ended.

Completion does not describe durability

After DONE, obtain affected-row counts or generated identifiers through the documented connection APIs before unrelated work changes those connection-local values. If the statement is inside an explicit transaction, record the later commit result separately; DONE alone does not prove durable commit. For statements with RETURNING clauses, consume every ROW before expecting DONE; stopping after the first returned row leaves the statement active and can retain locks longer than intended.

Questions that narrow SQLITE_E_DONE

QuestionDiagnostic direction
Same input rejected elsewhereAgreement at the same offset supports a representation or contract cause
Known-good sample fails locallyAttention shifts to local libraries, state, packaging, or configuration
Clean process behaves differentlyLook for mutation, leaked state, concurrency, or cached negotiation
Boundary control no longer failsValidation may have been disabled rather than corrected

Preserve causal order for SQLITE_E_DONE

Timestamp acquisition, parsing or preparation, the call returning SQLITE_E_DONE, automatic retry, and cleanup so a later network, storage, or disposal result cannot replace the original cause.

SQLite object lifetimes for SQLITE_E_DONE

ObjectRecord
Database connectionOpen flags, threading mode, transaction state, and latest connection error
Prepared statementSQL identity, bindings, prepare API, and step call
Current rowColumn values governed by the documented SQLITE_ROW lifetime
Log callbackExtended code and message retained even when the active API succeeds

Native SQLite identity behind SQLITE_E_DONE

Keep the primary and extended SQLite result before mapping it to SQLITE_E_DONE, because masking the low byte or treating every HRESULT alike can erase the distinction among ROW, DONE, NOTICE, WARNING, and an extended warning.

Cleanup paths for SQLITE_E_DONE

  • Finalize every statement that will not be reused
  • Reset reusable statements only at a documented terminal state
  • Avoid recursive SQLite use from the configured log callback
  • Verify rollback, commit, and close independently from this result

Decision boundary for SQLITE_E_DONE

EvidenceUse
Direct API returnDetermines control flow for prepare, step, reset, finalize, or transaction work
Extended result codePreserves the specific SQLite condition before HRESULT translation
Log callback eventAdds diagnostics but does not automatically replace the direct API result
Transaction outcomeSeparately determines whether completed statement work becomes durable

Technical references for SQLITE_E_DONE


Looking for a different code? Search another status or error code.