/****************************************************************************** * Copyright (C) 2012, 2013, 2014, 2015, 2016 * Younghyung Cho. <yhcting77@gmail.com> * All rights reserved. * * This file is part of NetMBuddy * * This program is licensed under the FreeBSD license * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the FreeBSD Project. *****************************************************************************/ package free.yhc.netmbuddy.db; import android.database.sqlite.SQLiteDatabase; import free.yhc.baselib.Logger; import free.yhc.netmbuddy.db.DB.Col; class DBUpgrader { private static final boolean DBG = Logger.DBG_DEFAULT; private static final Logger P = Logger.create(DBUpgrader.class, Logger.LOGLV_DEFAULT); private final SQLiteDatabase mDb; private final int mOldVersion; private final int mNewVersion; DBUpgrader(SQLiteDatabase db, int oldVersion, int newVersion) { mDb = db; mOldVersion = oldVersion; mNewVersion = newVersion; } private static String buildAddColumnSQL(String table, String col) { return "ALTER TABLE " + table + " ADD COLUMN " + col + ";"; } private static String buildAddColumnSQL(String table, Col col) { return buildAddColumnSQL(table, DBUtils.buildColumnDef(col)); } private static void execDropColumns(SQLiteDatabase db , String table, String tempTable, Col[] dbCols, @SuppressWarnings("unused") String[] unusedCols) { // SQLITE doesn't support 'DROP COLUMN'. // This is heavy workaround. // create temp table. db.execSQL(DBUtils.buildTableSQL(tempTable, dbCols)); // copy columns that should be preserved. String[] dbColNames = new String[dbCols.length]; for (int i = 0; i < dbCols.length; i++) dbColNames[i] = dbCols[i].getName(); db.execSQL(DBUtils.buildCopyColumnsSQL(tempTable, table, dbColNames)); // Drop current table. db.execSQL("DROP TABLE " + table + ";"); // Rename newly generated temp table into real table name db.execSQL("ALTER TABLE " + tempTable + " RENAME TO " + table + ";"); } private static void upgradeTo2(SQLiteDatabase db) { // Reserved column is useless. // Because, it's very difficult to maintain DB itself. // Adding column is not expensive operation. // In consequence, "Adding reserved fields" was BIG MISTAKE :-( // So, reserved columns and other unused columns are removed at DB version 4. db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), ColPlaylist.THUMBNAIL_YTVID)); // Playlist - Columes dropped at later version.(hardcoded-name is used instead of enum) db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), "reserved0 text \"\"")); db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), "reserved1 text \"\"")); db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), "reserved2 integer 0")); db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), "reserved3 integer 0")); db.execSQL(buildAddColumnSQL(DB.getPlaylistTableName(), "reserved4 blob \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), ColVideo.NRPLAYED)); // Video - Columes dropped at later version.(hardcoded-name is used instead of enum) db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "author text \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "relvideosfeed text \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved0 text \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved1 text \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved2 text \"\"")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved3 integer 0")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved4 integer 0")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved5 integer 0")); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), "reserved6 blob \"\"")); } private static void upgradeTo3(SQLiteDatabase db) { db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), ColVideo.BOOKMARKS)); } private static void upgradeTo4(SQLiteDatabase db) { final String tempTableName = "____TEMP____"; final String[] playlistDeprecatedColumns = { "reserved0", "reserved1", "reserved2", "reserved3", "reserved4" }; final String[] videoDeprecatedColumns = { "author", "relvideosfeed", "genre", "artist", "album", "rate", "reserved0", "reserved1", "reserved2", "reserved3", "reserved4", "reserved5", "reserved6" }; // Add new columns db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), ColVideo.CHANNELID)); db.execSQL(buildAddColumnSQL(DB.getVideoTableName(), ColVideo.CHANNELTITLE)); execDropColumns(db, DB.getPlaylistTableName(), tempTableName, ColPlaylist.values(), playlistDeprecatedColumns); execDropColumns(db, DB.getVideoTableName(), tempTableName, ColVideo.values(), videoDeprecatedColumns); } void upgrade() { int dbv = mOldVersion; mDb.beginTransaction(); try { while (dbv < mNewVersion) { switch (dbv) { case 1: upgradeTo2(mDb); break; case 2: upgradeTo3(mDb); break; case 3: upgradeTo4(mDb); break; } dbv++; } mDb.setTransactionSuccessful(); } finally { mDb.endTransaction(); } } }