views:

107

answers:

2

I am getting an error from Logcat saying that a certain column (in my SQLiteOpenHelper subclass) does not exist. I thought I could upgrade the database by changing the DATABASE_CREATE string. But apparently not, so how can I (step-by-step) upgrade my SQLite Database from version 1 to version 2? I apologize if the question seems "noobish", but I am still learning about Android.
@Pentium10 This is what I do in onUpgrade:

private static final int DATABASE_VERSION = 1;

....

switch (upgradeVersion) {
case 1:
    db.execSQL("ALTER TABLE task ADD body TEXT");
    upgradeVersion = 2;
    break;
}

...
+1  A: 

Ok, before you run into bigger problems you should know that SQLite is limited on the ALTER TABLE command, it allows add and rename only no remove/drop which is done with recreation of the table.

You should always have the new table creation query at hand, and use that for upgrade and transfer any existing data. Note: that the onUpgrade methods runs one for your sqlite helper object and you need to handle all the tables in it.

So what is recommended onUpgrade:

  • beginTransaction
  • run a table creation with if not exists (we are doing an upgrade, so the table might not exists yet, it will fail alter and drop)
  • put in a list the existing columns List<String> columns = DBUtils.GetColumns(db, TableName);
  • backup table (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
  • create new table (the newest table creation schema)
  • get the intersection with the new columns, this time columns taken from the upgraded table (columns.retainAll(DBUtils.GetColumns(db, TableName));)
  • restore data (String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName)); )
  • remove backup table (DROP table 'temp_" + TableName)
  • setTransactionSuccessful

.

public static List<String> GetColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("select * from " + tableName + " limit 1", null);
        if (c != null) {
            ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
        }
    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null)
            c.close();
    }
    return ar;
}

public static String join(List<String> list, String delim) {
    StringBuilder buf = new StringBuilder();
    int num = list.size();
    for (int i = 0; i < num; i++) {
        if (i != 0)
            buf.append(delim);
        buf.append((String) list.get(i));
    }
    return buf.toString();
}
Pentium10
+100 That was VERY specific! Thanks for the help!
Mohit Deshpande
Could I haved used CREATE TEMPORARY TABLE IF NOT EXISTS instead of CREATE TABLE IF NOT EXISTS?
Mohit Deshpande
No, as you will lose it when the connection drops. Always keep your table schema as `CREATE TABLE IF NOT EXISTS`
Pentium10
How does this incorporate the version of the database?
Mohit Deshpande
Everytime the onUpgrade method runs it detects a version change. You don't need to keep record of each change of your database (as in your question). You just need the **latest** table creation schema. The method I described creates a brand new table with the new table schema and transfers the existing records.
Pentium10
So am I doing it right in my code sample? Everytime I would change the DATABASE_VERSION up one. Then change the upgradeVersion up one?
Mohit Deshpande
When you edit a change in your table schemas you increase DATABASE_VERSION. As far I see you don't need the upgradeVersion.
Pentium10
So I use the switch statement for DATABASE_VERSION? Instead of oldVersion.
Mohit Deshpande
You probably don't understand clearly the idea I described. Why do you want to do a switch statement on the version? What do you want to do different for each version apart?
Pentium10
Ok so I would change create a new table schema based on the version. Then when I want to upgrade, I would change the schema again in the onUpgrade method? Could you please post a code sample including and onUpgrade in version 1 and onUpgrade in version 2. (Use whatever table schema)
Mohit Deshpande
My onUpgrade method just contains the above stuff, plus all of the code is inside of a cycle(on a list) where I step on all tables, so I do the upgrade on all tables.
Pentium10
I don't use the versions. You don't need. You always upgrade to latest version, you don't need to upgrade for all. Take this: you have v1, v10, v50, v80. And your current defined version is v100. Even if you upgrade from v1 or v50, you need to have the table schema of v100. So I just create **latest** (that means the v100) table schema and I don't bother what version I upgraded from. I don't need to know if it was v1 or v50, it's version independent. You always upgrade to latest and you don't need to know from what version.
Pentium10
Ok now I understand. Thank you for the clarification.
Mohit Deshpande
When you say "run a table creation" what do you mean?
Mohit Deshpande
create table if not exits query
Pentium10
What about downgrading? From v100 to v80? Since you can't delete columns...
Mohit Deshpande
AFAIK android does not support that.
Pentium10
A: 

If you've changed your SQLite table the easiest way to get things working again is to completely uninstall your application from the phone and then reinstall it. Go to Settings -> Applications -> Manage Applications to uninstall your app.

Zhehao Mao