I would guess when you do your migration you aren'...
# multiplatform
k
a
So during the migration process I am doing this:
Copy code
if (sqlite3_prepare_v2(encryptedDb.value, "PRAGMA user_version;", -1, sqliteStatementPointer.ptr, null) == SQLITE_OK ) {
   while(sqlite3_step(sqliteStatementPointer.value) == SQLITE_ROW) {
        sqlite3_bind_int(sqliteStatementPointer.value, 1, dbVersion)
    }
}
Where dbVersion is retrieved from the unencrypted DB. In this case the dbVersion is 1, so I am setting it to 1 here. You think it should dbVersion + 1?
k
I would expect it needs to match, not be a +1, but I don't know off hand just looking at that code if it's being set correctly.
If you're only migrating once, and it's always from version 1, I'd just run
PRAGMA user_version = 1
directly to make it simpler.
In any case, verify that that user_version is 1 before attempting to open sqldelight.
a
I see, it seems to be setting it all fine as I'm not running into any issues around the logic here
k
Well, I'm not sure why else it would attempt to create that table on sqldelight startup, so were it me, step 1 would be verifying the version is correct.
a
Yeah migration should only be done once as it is going from unencrypted to encrypted. I tried to return this:
Copy code
NativeSqliteDriver(DatabaseConfiguration(
          name = DatabaseName,
          version = 1,
          create = { connection -> wrapConnection(connection) { DatabaseSample.Schema.create(it) } },
//          upgrade = { connection, oldVersion, newVersion -> wrapConnection(connection) { DatabaseSample.Schema.migrate(it, oldVersion, newVersion) } },
//          Workaround for DatabaseConnection.setCipherKey causing an exception on iOS 14
          configConnection = { connection, _ ->
            val statement = "PRAGMA key = \"$password\";"
            connection.withStatement(statement) {
              stringForQuery()
            }
          }
        ))
but got the same issue. I'm not sure do I need to include the upgrade line or not, as this return is done after migrating the db Whole code for migration is this:
Copy code
val unencryptedDb: CPointerVar<sqlite3> = allocPointerTo()
        val encryptedDb: CPointerVar<sqlite3> = allocPointerTo()

        if (sqlite3_open(databasePath, unencryptedDb.ptr) == SQLITE_OK) {
          val exec1 = sqlite3_exec(unencryptedDb.value, "ATTACH DATABASE '$temporaryDatabasePath' AS encrypted KEY '$password';", null, null, null)
          val exec2 = sqlite3_exec(unencryptedDb.value, "SELECT sqlcipher_export('encrypted')", null, null, null)
          val exec3 = sqlite3_exec(unencryptedDb.value, "DETACH DATABASE encrypted;", null, null, null)

          val dbVersion = getUserVersion(unencryptedDb)
          sqlite3_close(unencryptedDb.value)

          if (sqlite3_open(temporaryDatabasePath, encryptedDb.ptr) == SQLITE_OK && dbVersion != null) {
            sqlite3_key(encryptedDb.value, password.cstr, password.cstr.size)
            val sqliteStatementPointer: CPointerVar<sqlite3_stmt> = allocPointerTo()

            if (sqlite3_prepare_v2(encryptedDb.value, "PRAGMA user_version;", -1, sqliteStatementPointer.ptr, null) == SQLITE_OK ) {
              while(sqlite3_step(sqliteStatementPointer.value) == SQLITE_ROW) {
                sqlite3_bind_int(sqliteStatementPointer.value, 1, dbVersion)
              }
            } else {
              sqlite3_errmsg(encryptedDb.value)
              NSLog("Error preparing: ${sqlite3_errmsg(encryptedDb.value)}")
            }

            sqlite3_finalize(sqliteStatementPointer.value)
          }

          sqlite3_close(unencryptedDb.value)
          sqlite3_close(encryptedDb.value)

          val error: ObjCObjectVar<NSError?> = alloc()
          val removeResult = fileManager.removeItemAtPath(databasePath, error.ptr)
So I'm not sure if my issue is the returning part of NativeSqliteDriver(DatabaseConfiguration) Sorry very long winded but thought might help understand the context of it more
k
Try this:
Copy code
NativeSqliteDriver(DatabaseConfiguration(
        name = DatabaseName,
        version = DatabaseSample.Schema.version,
        create = { connection -> wrapConnection(connection) { DatabaseSample.Schema.create(it) } },
//          upgrade = { connection, oldVersion, newVersion -> wrapConnection(connection) { DatabaseSample.Schema.migrate(it, oldVersion, newVersion) } },
//          Workaround for DatabaseConnection.setCipherKey causing an exception on iOS 14
        configConnection = { connection, _ ->
            val statement = "PRAGMA key = \"$password\";"
            connection.withStatement(statement) {
                stringForQuery()
            }
            if(connection.getVersion() != 1)
                throw IllegalStateException("wrong db version after migration")
        }
    ))
It's been a while, but I believe configConnection runs before sqldelight attempts to use the connection. I think you're still getting version 0 from the db, which makes the
create
process run, so check it with
Copy code
if(connection.getVersion() != 1)
                throw IllegalStateException("wrong db version after migration")
Remove that after this is fixed. That would be a problem long term, obviously.
a
Hey Kevin, you are right, it is still returning 0. You think this is an issue with this code
Copy code
if (sqlite3_prepare_v2(encryptedDb.value, "PRAGMA user_version;", -1, sqliteStatementPointer.ptr, null) == SQLITE_OK ) {
   while(sqlite3_step(sqliteStatementPointer.value) == SQLITE_ROW) {
        sqlite3_bind_int(sqliteStatementPointer.value, 1, dbVersion)
   }
as far as I know this should set the version to be 1, as the dbVersion is 1