Can't downgrade database from version `n` to `n-1` on Samsung
Asked Answered
P

3

13

I have an application with a database, created and opened using the standard SQLiteOpenHelper.

Whenever I upgrade the database version, I also upgrade the application's version code, so there is no way for the database to go down (the database version number is always increased, never decreased).

I disabled database backup in my app by setting the android:allowBackup property to false.

But when I upgrade the app on the Play Store, I get a lot of crash

Can't downgrade database from version n to n-1

96% of those crash occur on Samsung device running . Anyone know why this problem occurs, and more importantly how to prevent this crash ?

I know that I can override the onDowngrade to prevent the crash but I actually don't understand why the onDowngrade is called at all as the crash is called on an app that always use the last version of the database.

Edit : Added code sample, FWIW

My OpenHelper :

public class MyDBHelper extends SQLiteOpenHelper {

    private static final String LOG_TAG = MyDBHelper.class.getName();

    public static final String DB_NAME = "my_db";
    public static final int DB_V1 = 1;
    public static final int DB_V2_UNIQUE_IDS = 2;
    public static final int DB_V3_METADATAS = 3;
    public static final int DB_V4_CORRUPTED_IDS = 4;
    public static final int DB_V5_USAGE_TABLE = 5;

    public static final int DB_VERSION = DB_V5_USAGE_TABLE;

    public MyDBHelper(final Context context, IExceptionLogger logger) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(final SQLiteDatabase db) {
        Debug.log_d(DebugConfig.DEFAULT, LOG_TAG, "onCreate()");
        db.execSQL(createMyTable());
    }

    @Override
    public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
        Debug.log_d(DebugConfig.DEFAULT, LOG_TAG, "onUpgrade(): oldVersion = " + oldVersion + " : newVersion = " + newVersion);

        if (oldVersion < 2) {
            Debug.log_d(DebugConfig.DEFAULT, LOG_TAG, "onUpgrade(): upgrading version 1 table to version 2");
            db.execSQL(upgradeTable_v1_to_v2());
        }

        if (oldVersion < 3) {
            Debug.log_d(DebugConfig.DEFAULT, LOG_TAG, "onUpgrade(): upgrading version 2 Entry table to version 3");
            db.execSQL(upgradeTable_v2_to_v3());
        }
    }

    @Override
    @TargetApi(Build.VERSION_CODES.FROYO)
    public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
        Debug.log_d(DebugConfig.DEFAULT, LOG_TAG, "onDowngrade(): oldVersion = " + oldVersion + " : newVersion = " + newVersion);
        super.onDowngrade(db, oldVersion, newVersion);
    }
}

And how I initialize it :

public class DatabaseController {

    private MyDBHelper mDBHelper;

    public void initialize(final Context context) {

       mDBHelper = new MyDBHelper(context);

    }
}
Pawpaw answered 4/4, 2017 at 7:2 Comment(10)
are you able to see if those crashes come from rooted devices? on rooted devices users can downgrade apps if they choose toGraiae
99.9% of the device are not rooted.Pawpaw
are you maybe using the SQLiteOpenHelper with a version parameter somewhere in your project? If you're overriding SQLiteOpenHelper, make sure you're calling super in the constructor with the latest versionGraiae
Nope, the SQLiteOpen helper uses a static final constant int as it's version argument. Besides, if it was the case it would crash on all kind of devices and not just on SamsungsPawpaw
post your SQLiteOpenHelper class constructors, and onUpgrade methods, also, post some code on how you're using this class in some other code.Graiae
here mDBHelper = new DatabaseHelper(context) you meant mDBHelper = new MyDBHelper(context) ?Graiae
Yes sorry... meant to anonimize / cleanup my production code but missed onePawpaw
What are the reported n/n-1 values? Are they plausible?Hellenism
They are reported as downgrading from version 5 to 4, so basically downgrading from the current expected version to the previous versionPawpaw
You forgot to add the stacktrace for those crashes. This would have been a bit more obvious then.Phyllisphylloclade
D
9

This is the default implementation of SQLiteOpenHelper.onDowngrade(...):

public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    throw new SQLiteException("Can't downgrade database from version " +
            oldVersion + " to " + newVersion);
}

As you see if you call super.onDowngrade(...), as you do, you'll get that exception. You need to implement onDowngrade yourself, without calling super.onDowngrade. It should always be implemented for the sake of completeness, as there's no guarantee when it might be called - it sounds strange that the user has changed to use an older version of the app but there might be a situation like that. Do you know what version of the app the exceptions come from?

Dachshund answered 18/4, 2017 at 8:7 Comment(4)
This was so obvious that I didn't even notice the call to the super method... Note : The question at the end is not necessary, to downgrade a DB (for any reason), this need to be implemented, same for the upgrade.Phyllisphylloclade
If you had read my question, I said that I know I can override the onDowngrade method. My question was about why the onDowngrade was called for absolutely no reason !Pawpaw
Can you see what app version those crashes come from? That might give you some hint - if it's the latest version, the system is doing something strange.Dachshund
Seems that you're not the only one who's getting a strange downgrade to an earlier database version on Samsung devices only.Dachshund
B
0

Your comment in the @etan answer:

why the onDowngrade was called for absolutely no reason?

There is absolute reason,

public static final int DB_V5_USAGE_TABLE = 5;

public static final int DB_VERSION = DB_V5_USAGE_TABLE;

your DB_VERSION holds 5 and in your constructor, you are passing that value. Obviously argument for version should be greater than the previous version otherwise you will get this message.

As @etan expressed, if you need to downgrade the version you need to properly override the onDowngrade method instead throwing the error again.

You may be knew this, so please try to remember your previous version or try to pass 6 or greater for database version parameter.

Bluegrass answered 19/7, 2017 at 18:6 Comment(0)
E
0

You can solve this problem by remove "super.onDowngrade(db, oldVersion, newVersion);" line or comment it

@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  //super.onDowngrade(db, oldVersion, newVersion);
  Log.w(TAG, "Downgrade database from version " + oldVersion + " to " + newVersion);
}
Escolar answered 6/12, 2022 at 8:43 Comment(1)
Use for code formatting 4 spacesGranddaughter

© 2022 - 2024 — McMap. All rights reserved.