1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.DatabaseUtils; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.sqlite.SQLiteDatabase; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.sqlite.SQLiteFullException; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.sqlite.SQLiteQueryBuilder; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.sqlite.SQLiteStatement; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.SparseArray; 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BugleGservicesKeys; 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.DebugUtils; 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil; 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils; 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Locale; 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Stack; 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.regex.Pattern; 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class DatabaseWrapper { 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String TAG = LogUtil.BUGLE_DATABASE_TAG; 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final SQLiteDatabase mDatabase; 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final Context mContext; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final boolean mLog; 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Set mExplainQueryPlanRegexp (via {@link BugleGservicesKeys#EXPLAIN_QUERY_PLAN_REGEXP} 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * to regex matching queries to see query plans. For example, ".*" to show all query plans. 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // See 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final String mExplainQueryPlanRegexp; 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final int sTimingThreshold = 50; // in milliseconds 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final int INDEX_INSERT_MESSAGE_PART = 0; 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final int INDEX_INSERT_MESSAGE = 1; 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final int INDEX_QUERY_CONVERSATIONS_LATEST_MESSAGE = 2; 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final int INDEX_QUERY_MESSAGES_LATEST_MESSAGE = 3; 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final SparseArray<SQLiteStatement> mCompiledStatements; 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static class TransactionData { 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long time; 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd boolean transactionSuccessful; 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // track transaction on a per thread basis 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static ThreadLocal<Stack<TransactionData>> sTransactionDepth = 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd new ThreadLocal<Stack<TransactionData>>() { 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Stack<TransactionData> initialValue() { 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new Stack<TransactionData>(); 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static String[] sFormatStrings = new String[] { 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd "took %d ms to %s", 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd " took %d ms to %s", 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd " took %d ms to %s", 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd DatabaseWrapper(final Context context, final SQLiteDatabase db) { 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mLog = LogUtil.isLoggable(LogUtil.BUGLE_DATABASE_PERF_TAG, LogUtil.VERBOSE); 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mExplainQueryPlanRegexp = Factory.get().getBugleGservices().getString( 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd BugleGservicesKeys.EXPLAIN_QUERY_PLAN_REGEXP, null); 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase = db; 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mContext = context; 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mCompiledStatements = new SparseArray<SQLiteStatement>(); 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public SQLiteStatement getStatementInTransaction(final int index, final String statement) { 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Use transaction to serialize access to statements 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isTrue(mDatabase.inTransaction()); 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd SQLiteStatement compiled = mCompiledStatements.get(index); 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (compiled == null) { 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd compiled = mDatabase.compileStatement(statement); 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isTrue(compiled.toString().contains(statement.trim())); 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mCompiledStatements.put(index, compiled); 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return compiled; 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void maybePlayDebugNoise() { 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd DebugUtils.maybePlayDebugNoise(mContext, DebugUtils.DEBUG_SOUND_DB_OP); 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static void printTiming(final long t1, final String msg) { 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int transactionDepth = sTransactionDepth.get().size(); 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long t2 = System.currentTimeMillis(); 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long delta = t2 - t1; 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (delta > sTimingThreshold) { 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(LogUtil.BUGLE_DATABASE_PERF_TAG, String.format(Locale.US, 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sFormatStrings[Math.min(sFormatStrings.length - 1, transactionDepth)], 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd delta, 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd msg)); 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Context getContext() { 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return mContext; 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void beginTransaction() { 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long t1 = System.currentTimeMillis(); 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // push the current time onto the transaction stack 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final TransactionData f = new TransactionData(); 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd f.time = t1; 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sTransactionDepth.get().push(f); 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.beginTransaction(); 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void setTransactionSuccessful() { 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final TransactionData f = sTransactionDepth.get().peek(); 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd f.transactionSuccessful = true; 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.setTransactionSuccessful(); 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void endTransaction() { 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long transactionStartTime = 0; 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final TransactionData f = sTransactionDepth.get().pop(); 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (f.transactionSuccessful == false) { 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(TAG, "endTransaction without setting successful"); 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd for (final StackTraceElement st : (new Exception()).getStackTrace()) { 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(TAG, " " + st.toString()); 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd transactionStartTime = f.time; 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.endTransaction(); 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to endTransaction", ex); 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ">>> endTransaction (total for this transaction: %d)", 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd (System.currentTimeMillis() - transactionStartTime))); 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void yieldTransaction() { 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long yieldStartTime = 0; 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd yieldStartTime = System.currentTimeMillis(); 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final boolean wasYielded = mDatabase.yieldIfContendedSafely(); 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (wasYielded && mLog) { 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(yieldStartTime, "yieldTransaction"); 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void insertWithOnConflict(final String searchTable, final String nullColumnHack, 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ContentValues initialValues, final int conflictAlgorithm) { 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.insertWithOnConflict(searchTable, nullColumnHack, initialValues, 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd conflictAlgorithm); 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to insertWithOnConflict", ex); 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd "insertWithOnConflict with ", searchTable)); 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void explainQueryPlan(final SQLiteQueryBuilder qb, final SQLiteDatabase db, 198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] projection, final String selection, 199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @SuppressWarnings("unused") 200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] queryArgs, 201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String groupBy, 202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @SuppressWarnings("unused") 203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String having, 204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String sortOrder, final String limit) { 205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String queryString = qb.buildQuery( 206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd projection, 207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd selection, 208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd groupBy, 209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd null/*having*/, 210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sortOrder, 211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd limit); 212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd explainQueryPlan(db, queryString, queryArgs); 213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void explainQueryPlan(final SQLiteDatabase db, final String sql, 216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] queryArgs) { 217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!Pattern.matches(mExplainQueryPlanRegexp, sql)) { 218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return; 219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Cursor planCursor = db.rawQuery("explain query plan " + sql, queryArgs); 221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (planCursor != null && planCursor.moveToFirst()) { 223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int detailColumn = planCursor.getColumnIndex("detail"); 224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final StringBuilder sb = new StringBuilder(); 225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd do { 226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sb.append(planCursor.getString(detailColumn)); 227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sb.append("\n"); 228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } while (planCursor.moveToNext()); 229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (sb.length() > 0) { 230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sb.setLength(sb.length() - 1); 231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(TAG, "for query " + sql + "\nplan is: " 233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + sb.toString()); 234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final Exception e) { 236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(TAG, "Query plan failed ", e); 237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (planCursor != null) { 239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd planCursor.close(); 240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Cursor query(final String searchTable, final String[] projection, 245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String selection, final String[] selectionArgs, final String groupBy, 246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String having, final String orderBy, final String limit) { 247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mExplainQueryPlanRegexp != null) { 248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd qb.setTables(searchTable); 250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd explainQueryPlan(qb, mDatabase, projection, selection, selectionArgs, 251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd groupBy, having, orderBy, limit); 252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Cursor cursor = mDatabase.query(searchTable, projection, selection, selectionArgs, 260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd groupBy, having, orderBy, limit); 261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming( 263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1, 264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd String.format(Locale.US, "query %s with %s ==> %d", 265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd searchTable, selection, cursor.getCount())); 266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return cursor; 268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Cursor query(final String searchTable, final String[] columns, 271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String selection, final String[] selectionArgs, final String groupBy, 272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String having, final String orderBy) { 273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return query( 274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd searchTable, columns, selection, selectionArgs, 275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd groupBy, having, orderBy, null); 276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Cursor query(final SQLiteQueryBuilder qb, 279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] projection, final String selection, final String[] queryArgs, 280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String groupBy, final String having, final String sortOrder, final String limit) { 281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mExplainQueryPlanRegexp != null) { 282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd explainQueryPlan(qb, mDatabase, projection, selection, queryArgs, 283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd groupBy, having, sortOrder, limit); 284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Cursor cursor = qb.query(mDatabase, projection, selection, queryArgs, groupBy, 291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd having, sortOrder, limit); 292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming( 294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1, 295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd String.format(Locale.US, "query %s with %s ==> %d", 296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd qb.getTables(), selection, cursor.getCount())); 297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return cursor; 299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public long queryNumEntries(final String table, final String selection, 302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] selectionArgs) { 303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long retval = 309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd DatabaseUtils.queryNumEntries(mDatabase, table, selection, selectionArgs); 310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog){ 311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming( 312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1, 313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd String.format(Locale.US, "queryNumEntries %s with %s ==> %d", table, 314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd selection, retval)); 315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return retval; 317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public Cursor rawQuery(final String sql, final String[] args) { 320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mExplainQueryPlanRegexp != null) { 321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd explainQueryPlan(mDatabase, sql, args); 322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Cursor cursor = mDatabase.rawQuery(sql, args); 329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming( 331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1, 332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd String.format(Locale.US, "rawQuery %s ==> %d", sql, cursor.getCount())); 333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return cursor; 335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public int update(final String table, final ContentValues values, 338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String selection, final String[] selectionArgs) { 339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int count = 0; 345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd count = mDatabase.update(table, values, selection, selectionArgs); 347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to update", ex); 349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "update %s with %s ==> %d", 353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd table, selection, count)); 354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return count; 356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public int delete(final String table, final String whereClause, final String[] whereArgs) { 359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int count = 0; 365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd count = mDatabase.delete(table, whereClause, whereArgs); 367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to delete", ex); 369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, 373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd String.format(Locale.US, "delete from %s with %s ==> %d", table, 374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd whereClause, count)); 375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return count; 377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public long insert(final String table, final String nullColumnHack, 380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ContentValues values) { 381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long rowId = -1; 387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd rowId = mDatabase.insert(table, nullColumnHack, values); 389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to insert", ex); 391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "insert to %s", table)); 395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return rowId; 397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public long replace(final String table, final String nullColumnHack, 400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ContentValues values) { 401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long rowId = -1; 407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd rowId = mDatabase.replace(table, nullColumnHack, values); 409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to replace", ex); 411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "replace to %s", table)); 415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return rowId; 417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void setLocale(final Locale locale) { 420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.setLocale(locale); 421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void execSQL(final String sql, final String[] bindArgs) { 424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.execSQL(sql, bindArgs); 431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to execSQL", ex); 433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "execSQL %s", sql)); 438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void execSQL(final String sql) { 442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mDatabase.execSQL(sql); 449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to execSQL", ex); 451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "execSQL %s", sql)); 456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public int execSQLUpdateDelete(final String sql) { 460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd long t1 = 0; 461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd t1 = System.currentTimeMillis(); 463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd maybePlayDebugNoise(); 465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final SQLiteStatement statement = mDatabase.compileStatement(sql); 466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int rowsUpdated = 0; 467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd rowsUpdated = statement.executeUpdateDelete(); 469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (SQLiteFullException ex) { 470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, "Database full, unable to execSQLUpdateDelete", ex); 471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.db_full); 472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mLog) { 474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd printTiming(t1, String.format(Locale.US, "execSQLUpdateDelete %s", sql)); 475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return rowsUpdated; 477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public SQLiteDatabase getDatabase() { 480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return mDatabase; 481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 483