NordicSemiconductor / Android-nRF-Mesh-Library

The Bluetooth Mesh Provisioner and Configurator library.
https://www.nordicsemi.com/
BSD 3-Clause "New" or "Revised" License
414 stars 177 forks source link

Migration Issue in version 3.1.5 #418

Closed BubblyNetDev closed 3 years ago

BubblyNetDev commented 3 years ago

Describe the bug Running new release 3.1.5 after having run 2.1.3 the app crashes with the following exception.

E/CursorWindow: Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 7 columns.
E/AndroidRuntime: FATAL EXCEPTION: pool-2-thread-1
    Process: no.nordicsemi.android.nrfmeshprovisioner, PID: 27912
    java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
        at android.database.CursorWindow.nativeGetString(Native Method)
        at android.database.CursorWindow.getString(CursorWindow.java:475)
        at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53)
        at no.nordicsemi.android.mesh.MeshNetworkDb.migrateMeshNetwork11_12(MeshNetworkDb.java:1026)
        at no.nordicsemi.android.mesh.MeshNetworkDb.access$1300(MeshNetworkDb.java:55)
        at no.nordicsemi.android.mesh.MeshNetworkDb$12.migrate(MeshNetworkDb.java:399)
        at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:99)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:177)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:493)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:391)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:145)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:106)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:622)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:399)
        at no.nordicsemi.android.mesh.data.MeshNetworkDao_Impl.getMeshNetwork(MeshNetworkDao_Impl.java:460)
        at no.nordicsemi.android.mesh.MeshNetworkDb.lambda$loadNetwork$1(MeshNetworkDb.java:173)
        at no.nordicsemi.android.mesh.-$$Lambda$MeshNetworkDb$Lx_nOticRyYIhf1gJ5NjtiyshXQ.run(Unknown Source:16)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)

To Reproduce Steps to reproduce the behavior:

  1. Run app from tag 2.1.3
  2. Then run app from tag 3.1.5
  3. See error

Expected behavior App to run, I have checked against later versions and this exception is not thrown from at least 2.4.1 and up. Seems to fail on MIGRATION_11_12, confirmed working when going from 2.1.3 to 3.0.

roshanrajaratnam commented 3 years ago

@BubblyNetDev thanks for the report, did you have any data in the database?

BubblyNetDev commented 3 years ago

I had created a group but not added any nodes or anything else

roshanrajaratnam commented 3 years ago

Right i'll try that then.

BubblyNetDev commented 3 years ago

Hello Roshan, any news on this issue? Were you able to reproduce?

roshanrajaratnam commented 3 years ago

Hi been a bit busy with some other things unfortunately. I'll try to take a look at this today.

Mavericksb commented 3 years ago

Had the same crash.

Should be because, in MeshNetworkDb.java, you have this method :

private static void addColumnNetworkExclusionList(@NonNull final SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE mesh_network ADD COLUMN network_exclusions TEXT NOT NULL DEFAULT '{}'");
}

And then migration method is called , which has : private static void migrateMeshNetwork11_12(@NonNull final SupportSQLiteDatabase database) { .. final Cursor cursor = database.query("SELECT * FROM mesh_network"); if (cursor != null && cursor.moveToFirst()) { do { .. final String networkExclusions = cursor.getString(cursor.getColumnIndex("network_exclusions")); .. }

But the new column network_exclusions is not found , and the problem lies in the line : final Cursor cursor = database.query("SELECT * FROM mesh_network");

Reason : there is a known Android bug, for some reason the SELECT, under specific circumnstances, retrieves the table from cache, so you get the old mesh network table, before being altered in the first place in addColumnNetworkExclusionList method .

Fix: stupid and counterintuitive it may sound but just writing select and from in lower case fixes it, try to change the cursor declaration this way : final Cursor cursor = database.query("select * from mesh_network");

roshanrajaratnam commented 3 years ago

@BubblyNetDev sorry for the delayed reply as I have been busy with some other tasks. @Mavericksb I tried your fix and strangely enough it does seem to work. Thanks for taking the time to debug this.