Skip to content

Commit 4cfdea8

Browse files
committed
Fixed missing weight column if 3.12.0 was run
* Fixed missing weight column if version 3.12.0 was installed * To fix added another db version with an upgrade specifically from v5 to v6
1 parent fd4b902 commit 4cfdea8

File tree

3 files changed

+119
-15
lines changed

3 files changed

+119
-15
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalDbHelper.java

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import java.util.List;
4343

4444
public class OneSignalDbHelper extends SQLiteOpenHelper {
45-
static final int DATABASE_VERSION = 5;
45+
static final int DATABASE_VERSION = 6;
4646
private static final String DATABASE_NAME = "OneSignal.db";
4747

4848
private static final String INTEGER_PRIMARY_KEY_TYPE = " INTEGER PRIMARY KEY";
@@ -79,7 +79,8 @@ public class OneSignalDbHelper extends SQLiteOpenHelper {
7979
OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + COMMA_SEP +
8080
OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + COMMA_SEP +
8181
OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + COMMA_SEP +
82-
OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE +
82+
// "params TEXT" Added in v4, removed in v5.
83+
OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + // New in v5, missing migration added in v6
8384
");";
8485

8586
private static final String SQL_CREATE_UNIQUE_OUTCOME_NOTIFICATION_ENTRIES =
@@ -166,20 +167,24 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
166167

167168
private static void internalOnUpgrade(SQLiteDatabase db, int oldVersion) {
168169
if (oldVersion < 2)
169-
upgradeFromV1ToV2(db);
170+
upgradeToV2(db);
170171

171172
if (oldVersion < 3)
172-
upgradeFromV2ToV3(db);
173+
upgradeToV3(db);
173174

174175
if (oldVersion < 4)
175176
upgradeToV4(db);
176177

177178
if (oldVersion < 5)
178179
upgradeToV5(db);
180+
181+
// Specifically running only when going from 5 to 6+ is intentional
182+
if (oldVersion == 5)
183+
upgradeFromV5ToV6(db);
179184
}
180185

181186
// Add collapse_id field and index
182-
private static void upgradeFromV1ToV2(SQLiteDatabase db) {
187+
private static void upgradeToV2(SQLiteDatabase db) {
183188
safeExecSQL(db,
184189
"ALTER TABLE " + NotificationTable.TABLE_NAME + " " +
185190
"ADD COLUMN " + NotificationTable.COLUMN_NAME_COLLAPSE_ID + TEXT_TYPE + ";"
@@ -189,7 +194,7 @@ private static void upgradeFromV1ToV2(SQLiteDatabase db) {
189194

190195
// Add expire_time field and index.
191196
// Also backfills expire_time to create_time + 72 hours
192-
private static void upgradeFromV2ToV3(SQLiteDatabase db) {
197+
private static void upgradeToV3(SQLiteDatabase db) {
193198
safeExecSQL(db,
194199
"ALTER TABLE " + NotificationTable.TABLE_NAME + " " +
195200
"ADD COLUMN " + NotificationTable.COLUMN_NAME_EXPIRE_TIME + " TIMESTAMP" + ";"
@@ -209,7 +214,43 @@ private static void upgradeToV4(SQLiteDatabase db) {
209214
}
210215

211216
private static void upgradeToV5(SQLiteDatabase db) {
217+
// Added for 3.12.1
212218
safeExecSQL(db, SQL_CREATE_UNIQUE_OUTCOME_NOTIFICATION_ENTRIES);
219+
// Added for 3.12.2
220+
upgradeOutcomeTableRevision1To2(db);
221+
}
222+
223+
// We only want to run this if going from DB v5 to v6 specifically since
224+
// it was originally missed in upgradeToV5 in 3.12.1
225+
// Added for 3.12.2
226+
private static void upgradeFromV5ToV6(SQLiteDatabase db) {
227+
upgradeOutcomeTableRevision1To2(db);
228+
}
229+
230+
// On the outcome table this adds the new weight column and drops params column.
231+
private static void upgradeOutcomeTableRevision1To2(SQLiteDatabase db) {
232+
String commonColumns = "_id,name,session,timestamp,notification_ids";
233+
try {
234+
// Since SQLite does not support dropping a column we need to:
235+
// 1. Create a temptable
236+
// 2. Copy outcome table into it
237+
// 3. Drop the outcome table
238+
// 4. Recreate it with the correct fields
239+
// 5. Copy the temptable rows back into the new outcome table
240+
// 6. Drop the temptable.
241+
db.execSQL("BEGIN TRANSACTION;");
242+
db.execSQL("CREATE TEMPORARY TABLE outcome_backup(" + commonColumns + ");");
243+
db.execSQL("INSERT INTO outcome_backup SELECT " + commonColumns + " FROM outcome;");
244+
db.execSQL("DROP TABLE outcome;");
245+
db.execSQL(SQL_CREATE_OUTCOME_ENTRIES);
246+
// Not converting weight from param here, just set to zero.
247+
// 3.12.1 quickly replaced 3.12.0 so converting cache isn't critical.
248+
db.execSQL("INSERT INTO outcome (" + commonColumns + ", weight) SELECT " + commonColumns + ", 0 FROM outcome_backup;");
249+
db.execSQL("DROP TABLE outcome_backup;");
250+
db.execSQL("COMMIT;");
251+
} catch (SQLiteException e) {
252+
e.printStackTrace();
253+
}
213254
}
214255

215256
private static void safeExecSQL(SQLiteDatabase db, String sql) {

OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalDbHelper.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88

99
@Implements(OneSignalDbHelper.class)
1010
public class ShadowOneSignalDbHelper {
11-
12-
public static final String DATABASE_NAME = "OneSignal.db";
13-
public static int DATABASE_VERSION = 5;
11+
public static int DATABASE_VERSION;
1412
public static boolean ignoreDuplicatedFieldsOnUpgrade;
1513

1614
private static OneSignalDbHelper sInstance;

OneSignalSDK/unittest/src/test/java/com/test/onesignal/DatabaseRunner.java

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.onesignal.StaticResetHelper;
1616

1717
import org.json.JSONArray;
18+
import org.junit.After;
1819
import org.junit.AfterClass;
1920
import org.junit.Before;
2021
import org.junit.BeforeClass;
@@ -33,6 +34,7 @@
3334
import static com.test.onesignal.TestHelpers.getAllUniqueOutcomeNotificationRecords;
3435
import static junit.framework.Assert.assertEquals;
3536
import static junit.framework.Assert.assertFalse;
37+
import static junit.framework.Assert.assertTrue;
3638

3739
@Config(packageName = "com.onesignal.example",
3840
instrumentedPackages = { "com.onesignal" },
@@ -51,14 +53,19 @@ public static void setUpClass() throws Exception {
5153
StaticResetHelper.saveStaticValues();
5254
}
5355

54-
@Before // Before each test
56+
@Before
5557
public void beforeEachTest() throws Exception {
5658
TestHelpers.beforeTestInitAndCleanup();
5759
}
5860

61+
@After
62+
public void afterEachTest() throws Exception {
63+
TestHelpers.afterTestCleanup();
64+
}
65+
5966
@AfterClass
6067
public static void afterEverything() throws Exception {
61-
StaticResetHelper.restSetStaticFields();
68+
TestHelpers.beforeTestInitAndCleanup();
6269
}
6370

6471
@Test
@@ -131,13 +138,25 @@ public void shouldUpgradeDbFromV3ToV4() throws Exception {
131138
assertEquals(outcomeEvents.size(), 1);
132139
}
133140

141+
142+
private static final String SQL_CREATE_OUTCOME_REVISION1_ENTRIES =
143+
"CREATE TABLE outcome (" +
144+
"_id INTEGER PRIMARY KEY, " +
145+
"session TEXT," +
146+
"notification_ids TEXT, " +
147+
"name TEXT, " +
148+
"timestamp TIMESTAMP, " +
149+
"params TEXT " +
150+
")";
151+
134152
@Test
135153
public void shouldUpgradeDbFromV4ToV5() {
136154
// 1. Init DB as version 4
137155
ShadowOneSignalDbHelper.DATABASE_VERSION = 4;
138-
SQLiteDatabase readableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getReadableDatabase();
156+
SQLiteDatabase writableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
157+
writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION1_ENTRIES);
139158

140-
Cursor cursor = readableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + CachedUniqueOutcomeNotificationTable.TABLE_NAME + "'", null);
159+
Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + CachedUniqueOutcomeNotificationTable.TABLE_NAME + "'", null);
141160

142161
boolean exist = false;
143162
if (cursor != null) {
@@ -147,7 +166,7 @@ public void shouldUpgradeDbFromV4ToV5() {
147166
// 2. Table must not exist
148167
assertFalse(exist);
149168

150-
readableDatabase.close();
169+
writableDatabase.close();
151170

152171
CachedUniqueOutcomeNotification notification = new CachedUniqueOutcomeNotification("notificationId", "outcome");
153172
ContentValues values = new ContentValues();
@@ -163,7 +182,7 @@ public void shouldUpgradeDbFromV4ToV5() {
163182

164183
assertEquals(notifications.size(), 0);
165184

166-
SQLiteDatabase writableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
185+
writableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
167186
// 5. Table now must exist
168187
writableDatabase.insert(CachedUniqueOutcomeNotificationTable.TABLE_NAME, null, values);
169188
writableDatabase.close();
@@ -172,4 +191,50 @@ public void shouldUpgradeDbFromV4ToV5() {
172191

173192
assertEquals(uniqueOutcomeNotifications.size(), 1);
174193
}
194+
195+
@Test
196+
public void shouldUpgradeDbFromV5ToV6() {
197+
// 1. Init outcome table as version 5
198+
SQLiteDatabase writableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
199+
200+
// Create table with the schema we had in DB v4
201+
writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION1_ENTRIES);
202+
203+
// Insert one outcome record so we can test migration keeps it later on
204+
ContentValues values = new ContentValues();
205+
values.put("name", "a");
206+
writableDatabase.insertOrThrow("outcome", null, values);
207+
writableDatabase.setVersion(5);
208+
writableDatabase.close();
209+
210+
// 2. restSetStaticFields so the db reloads and upgrade is done to version 6
211+
ShadowOneSignalDbHelper.restSetStaticFields();
212+
writableDatabase = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
213+
214+
// 3. Ensure the upgrade kept our existing record
215+
Cursor cursor = writableDatabase.query(
216+
"outcome",
217+
null,
218+
null,
219+
null,
220+
null,
221+
null,
222+
null
223+
);
224+
assertTrue(cursor.moveToFirst());
225+
assertEquals("a", cursor.getString(cursor.getColumnIndex("name")));
226+
227+
// 4. Ensure new weight column exists
228+
values = new ContentValues();
229+
values.put("weight", 1);
230+
long successful = writableDatabase.insert("outcome", null, values);
231+
assertFalse(successful == -1);
232+
233+
// 5. Ensure params column does NOT exists
234+
values = new ContentValues();
235+
values.put("params", 1);
236+
successful = writableDatabase.insert("outcome", null, values);
237+
writableDatabase.close();
238+
assertEquals(-1, successful);
239+
}
175240
}

0 commit comments

Comments
 (0)