问题
I've been getting an inconsistent, non-reproducible crash upon users upgrading to a new version of the local SQLite DB when updating the app.
Fatal Exception: android.database.sqlite.SQLiteException: duplicate column name: upload_pending (code 1): , while compiling: ALTER TABLE purchases ADD COLUMN upload_pending TINYINT DEFAULT 0
#################################################################
Error Code : 1 (SQLITE_ERROR)
Caused By : SQL(query) error or missing database.
(duplicate column name: upload_pending (code 1): , while compiling: ALTER TABLE purchases ADD COLUMN upload_pending TINYINT DEFAULT 0)
#################################################################
The column is new to this version of the app, which tells me the most likely bug is that SQLiteOpenHelper's onUpgrade method is being called twice. Here is the logic for how upgrade is handled:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
for(int currentUpgrade = oldVersion + 1; currentUpgrade <= newVersion; currentUpgrade++) {
switch(currentUpgrade) {
case 2:
//upgrade to db v2
break;
case 3:
//upgrade to db v3
break;
//etc
case 7:
methodWhichUpdatesAnotherTable(db);
db.execSQL("ALTER TABLE " + Purchases.TABLE_NAME
+ " ADD COLUMN " + Purchases.UPLOAD_PENDING + " TINYINT DEFAULT 0");
break;
}
}
}
EDIT: I've updated the code to include something important. The failing line is NOT the first ALTER statement in the upgrade. First, a method is called which makes two different alter statements (on a different table), and this portion works fine. This seems to eliminate the possibility that it's a concurrency issue, because if so these would be the first to fail.
Looking at this, the only way I can see this happening is if Android is calling onUpgrade twice, and not adjusting the oldVersion
and newVersion
params, resulting in case 7 being called twice. Conversely, it could be the case where onCreate is called, and onUpgrade is called afterwards, again with the database versions provided to the method not being correct.
As I mentioned at the start, I'm unable to reproduce this error, and it's only happening to <1% of users, but it is noticeable enough for me to want to solve it. If anyone has a guess I'd appreciate it, and if you need more info feel free to ask. Thanks!
回答1:
Had the same issue. Turned out, that I was creating the table for oldVersions before 4 and adding column for versions before 10. Because of that, both statements, CREATE TABLE and ALTER TABLE ADD COLUMN were executed for oldVersions pre 4:
if ( oldVersion < 4 && newVersion >= 4 ) {
TestTableDao.createTable( db, true );
}
if ( oldVersion < 10 && newVersion >= 10 ) {
db.execSQL( "ALTER TABLE TEXT_TABLE ADD COLUMN NEW_COLUMN TEXT" );
}
The fix was to check oldVersion for being after creation of table:
if ( oldVersion < 10 && newVersion >= 10 ) {
if( oldVersion >=4 )
db.execSQL( "ALTER TABLE TEXT_TABLE ADD COLUMN NEW_COLUMN TEXT" );
}
Hope it helps to someone.
来源:https://stackoverflow.com/questions/43356823/duplicate-column-name-on-sqlite-upgrade-for-a-new-column