Skip to content

SQLCipherStatement.getColumnType returns Cursor.FIELD_TYPE_NULL (0) instead of SQLITE_DATA_NULL (5), breaking room3-sqlite-wrapper on NULL columns #93

Description

@ZoeyJones

Summary

net.zetetic.database.sqlcipher.driver.SQLCipherStatement implements androidx.sqlite.SQLiteStatement, and its getColumnType(int) should return androidx.sqlite's SQLITE_DATA_* constants. It currently returns android.database.Cursor.getType(index) unchanged. The two agree for INTEGER, FLOAT, TEXT and BLOB (1–4), but NULL is Cursor.FIELD_TYPE_NULL = 0 versus SQLITE_DATA_NULL = 5. So every NULL column reports 0.

Affected: 4.18.0 (where the Room 3 driver was added), 4.19.0, and master @ bc71616.

Impact

Code that switches on the contract constants fails on the first NULL value. With Room 3's room3-sqlite-wrapper, roomDatabase.getSupportWrapper().query(...) throws while building the Cursor:

java.lang.IllegalStateException: Unknown column type: 0
  at androidx.room3.support.RoomSupportSQLite.toCursor(RoomSupportSQLite.kt:126)
  at androidx.room3.support.RoomSupportSQLiteDatabase$query$1$1.invokeSuspend(RoomSupportSQLiteDatabase.kt:154)
  at androidx.room3.coroutines.PassthroughConnection.usePrepared(PassthroughConnectionPool.kt:165)
  ...

We hit this in a production app migrating to Room 3: its ContentProvider queries go through getSupportWrapper(), and they crashed on rows with NULL columns. Room-generated DAO code uses isNull(), so plain DAO usage isn't affected.

Minimal reproduction

System.loadLibrary("sqlcipher")
val connection = SQLCipherDriver("pw".toByteArray(), null, null).open(dbFile.absolutePath)
connection.prepare("SELECT NULL").use { statement ->
    statement.step()
    statement.getColumnType(0) // expected SQLITE_DATA_NULL (5), actual 0
}

Reference fix

A fix with two instrumented tests is in a personal fork. It is not submitted as a PR here, pending your contributor-agreement process: ZoeyJones#1

  • It maps each Cursor.FIELD_TYPE_* to the matching SQLite.SQLITE_DATA_* explicitly, and throws on an unknown value.
  • The tests fail on unmodified master (expected:<5> but was:<0>, and the Unknown column type: 0 above).
  • With the fix, the whole net.zetetic.database.sqlcipher.driver package passes: 37/37 on an API 36 arm64 emulator.

Thank you for maintaining SQLCipher for Android.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions