package org.liberty.android.fantastischmemo.common; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; import org.liberty.android.fantastischmemo.dao.CardDao; import org.liberty.android.fantastischmemo.dao.CategoryDao; import org.liberty.android.fantastischmemo.dao.DeckDao; import org.liberty.android.fantastischmemo.dao.FilterDao; import org.liberty.android.fantastischmemo.dao.LearningDataDao; import org.liberty.android.fantastischmemo.dao.SettingDao; import org.liberty.android.fantastischmemo.entity.Card; import org.liberty.android.fantastischmemo.entity.Category; import org.liberty.android.fantastischmemo.entity.Deck; import org.liberty.android.fantastischmemo.entity.Filter; import org.liberty.android.fantastischmemo.entity.LearningData; import org.liberty.android.fantastischmemo.entity.Setting; import java.sql.SQLException; public class AnyMemoDBOpenHelper extends OrmLiteSqliteOpenHelper { private final String TAG = getClass().getSimpleName(); private final String dbPath; private static final int CURRENT_VERSION = 5; private CardDao cardDao = null; private DeckDao deckDao = null; private SettingDao settingDao = null; private FilterDao filterDao = null; private CategoryDao categoryDao = null; private LearningDataDao learningDataDao = null; private boolean isReleased = false; @Override public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) { Log.v(TAG, "Now we are creating a new database!"); Log.i(TAG, "Newly created db version: " + database.getVersion()); try { TableUtils.createTable(connectionSource, Card.class); TableUtils.createTable(connectionSource, Deck.class); TableUtils.createTable(connectionSource, Setting.class); TableUtils.createTable(connectionSource, Filter.class); TableUtils.createTable(connectionSource, Category.class); TableUtils.createTable(connectionSource, LearningData.class); getSettingDao().create(new Setting()); getCategoryDao().create(new Category()); if (database.getVersion() == 0) { convertOldDatabase(database); } } catch (SQLException e) { throw new RuntimeException("Database creation error: " + e.toString()); } } /* Convert database from AnyMemo < 9.0 */ private void convertOldDatabase(SQLiteDatabase database) { Cursor res = database.rawQuery("select name from sqlite_master where type = 'table' and name = 'dict_tbl'", null); boolean isOldDatabase = res.getCount() > 0; res.close(); // This is old database if (isOldDatabase) { // copy all cards database.execSQL("insert into cards (ordinal, question, answer, note)" + " select _id as ordinal, question, answer, note from dict_tbl"); // Make sure the count matches in old database; int count_dict = 0, count_learn = 0; Cursor result = database.rawQuery("SELECT _id FROM dict_tbl", null); count_dict = result.getCount(); result.close(); result = database.rawQuery("SELECT _id FROM learn_tbl", null); count_learn = result.getCount(); result.close(); if(count_learn != count_dict){ database.execSQL("DELETE FROM learn_tbl"); database.execSQL("INSERT INTO learn_tbl(_id) SELECT _id FROM dict_tbl"); database.execSQL("UPDATE learn_tbl SET date_learn = '2010-01-01', interval = 0, grade = 0, easiness = 2.5, acq_reps = 0, ret_reps = 0, lapses = 0, acq_reps_since_lapse = 0, ret_reps_since_lapse = 0"); } // copy learning data database.execSQL("update cards set learningData_id = (" + " select _id as learningData_id" + " from learn_tbl where learn_tbl._id = cards.id)"); database.execSQL("insert into learning_data (acqReps, acqRepsSinceLapse, easiness," + " grade, lapses, lastLearnDate, nextLearnDate, retReps, " + " retRepsSinceLapse)" + " select acq_reps as acqReps , acq_reps_since_lapse as acqRepsSinceLapse," + " easiness, grade, lapses," + " date_learn || ' 00:00:00.000000' as lastLearnDate," + " datetime(julianday(date_learn) + interval) || '.000000' as nextLearnDate," + " ret_reps as retReps, ret_reps_since_lapse as retRepsSinceLapse" + " from learn_tbl"); // copy categories database.execSQL("insert into categories (name)" + " select category as name from dict_tbl where category != ''" + " and category is not null" + " group by category"); database.execSQL("update cards set category_id = (" + " select id as category_id from categories as cat" + " join dict_tbl as dic on dic.category = cat.name" + " where cards.id = dic._id)"); // Update category if the category is null database.execSQL("update cards " + " set category_id = 1" + " where category_id is null"); database.execSQL("update cards set updateDate='2010-01-01 00:00:00.000000'," + "creationDate='2010-01-01 00:00:00.000000'"); database.execSQL("update categories set updateDate='2010-01-01 00:00:00.000000'"); database.execSQL("update learning_data set updateDate='2010-01-01 00:00:00.000000'"); // Set unused fields database.execSQL("update cards" + " set cardType = 0"); } } @Override public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) { Log.v(TAG, "Old version" + oldVersion + " new version: " + newVersion); // Update possible card with null category field if (oldVersion <= 2) { database.execSQL("update cards " + " set category_id = 1" + " where category_id is null"); } if (oldVersion <= 3) { database.execSQL("update settings set questionTextColor = ? where questionTextColor = ?", new Object[] {null, 0xFFBEBEBE}); database.execSQL("update settings set answerTextColor = ? where answerTextColor = ?", new Object[] {null, 0xFFBEBEBE} ); database.execSQL("update settings set questionBackgroundColor = ? where questionBackgroundColor = ?", new Object[] {null, 0xFF000000}); database.execSQL("update settings set answerBackgroundColor = ? where answerBackgroundColor = ?", new Object[] {null, 0xFF000000}); } if (oldVersion <= 4) { try { database.execSQL("alter table learning_data add column firstLearnDate VARCHAR"); database.execSQL("update learning_data set firstLearnDate='2010-01-01 00:00:00.000000'"); } catch (android.database.SQLException e) { Log.e(TAG, "Upgrading failed, the column firstLearnData might already exists.", e); } } } @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, String.format("Downgrading database from version %1$d to %2$d", oldVersion, newVersion)); } /** * Do not call this method directly, use AnyMemoDBOpenHelperManager instead. */ @Override public void close() { isReleased = true; try { DatabaseConnection connection = getConnectionSource().getReadWriteConnection(); getConnectionSource().releaseConnection(connection); } catch (SQLException e) { Log.e(TAG, "Error releasing the connection.", e); } super.close(); } public synchronized CardDao getCardDao() { try { if (cardDao == null) { cardDao = getDao(Card.class); cardDao.setHelper(this); } return cardDao; } catch (SQLException e) { throw new RuntimeException(e); } } public synchronized DeckDao getDeckDao() { try { if (deckDao == null) { deckDao = getDao(Deck.class); } return deckDao; } catch (SQLException e) { throw new RuntimeException(e); } } public synchronized SettingDao getSettingDao() { try { if (settingDao == null) { settingDao = getDao(Setting.class); } return settingDao; } catch (SQLException e) { throw new RuntimeException(e); } } public synchronized FilterDao getFilterDao() { try { if (filterDao == null) { filterDao = getDao(Filter.class); } return filterDao; } catch (SQLException e) { throw new RuntimeException(e); } } public synchronized CategoryDao getCategoryDao() { try { if (categoryDao == null) { categoryDao = getDao(Category.class); } return categoryDao; } catch (SQLException e) { throw new RuntimeException(e); } } public synchronized LearningDataDao getLearningDataDao() { try { if (learningDataDao == null) { learningDataDao = getDao(LearningData.class); } return learningDataDao; } catch (SQLException e) { throw new RuntimeException(e); } } /* * Override the finalize in case the helper is not release. */ @Override public void finalize() throws Throwable { super.finalize(); // If the finalize kicked in before the db is released. // force release the helper! // This is usually a bug in program. if (!isReleased) { Log.w(TAG, "AnyMemoDBOpenHelper for db " + dbPath + " is not released before being GCed. This class must be explicitly released! Force releasing now."); AnyMemoDBOpenHelperManager.forceRelease(dbPath); } } /* Package private constructor used in Manager. */ AnyMemoDBOpenHelper(Context context, String dbpath) { // R.raw.ormlite_config is used to accelerate the DAO creation. super(context, dbpath, null, CURRENT_VERSION); this.dbPath = dbpath; } /* Package private getDbPath used in Manager. */ String getDbPath() { return dbPath; } }