Site icon EfmSoft

What does HRESULT 0x87AF0064 (SQLITE_E_ROW) mean?

 
Previous Next
SQLITE_E_WARNING SQLITE_E_DONE

SQLITE_E_ROW

SQLITE_E_ROW (0x87AF0064) represents sqlite3_step has produced one result row. This HRESULT wraps SQLite result code 100. It is a control-flow result, not an error: column values for the current row are available until the statement is stepped again, reset, or finalized. Apply the native SQLite state-machine rules even though Windows stores the result in an HRESULT facility.

Correct loop contract

  1. Call sqlite3_step on a prepared statement
  2. Read every required column while the result is SQLITE_ROW
  3. Step again until SQLITE_DONE or an actual error is returned

Lifetime rules

ObjectBoundary
Column pointersText and blob pointers are tied to the current statement row.
BindingsBindings normally remain until cleared or rebound, but result data does not.
Reset/finalizeReset permits reuse; finalize releases the prepared statement.

Common bug pattern

Code that treats every nonzero SQLite result as failure will reject valid rows. The opposite bug is to process one row and assume the statement is complete without stepping to SQLITE_DONE.

Proof

A regression query with multiple rows must deliver each row once, end in DONE, and release or reset the statement on every exit path.

Read columns before advancing

Call sqlite3_column_type before conversions when NULL and dynamic typing matter, and copy text or blob data that must outlive the current row. A subsequent step, reset, or finalize can invalidate pointers returned by the column accessors even though the database connection remains open. Also verify that every expected column index is within the prepared statement’s result shape; a changed SELECT list is a contract change, not a ROW-state failure. Include an empty-result query and a row containing SQL NULL in the same regression suite.

Two independent axes

ComparisonWhat it reveals
Same artifact, different implementationWhether the representation is independently rejected
Known-good artifact, same environmentWhether the local stack fails without production-specific input
Original operation, one isolated changeWhether the proposed correction controls the observed result
Deliberate boundary violationWhether validation remains active after the change

Safe logging

Capture this result with the operation, byte count, parser or statement position, and contract version, replacing sensitive bodies with hashes and bounded excerpts without losing the state needed to reproduce the event.

SQLite object lifetimes

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 the result

Keep the primary and extended SQLite result before mapping it to this result, 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

Decision boundary

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


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

Exit mobile version