SQLiteDatabase.java revision d833023307494d5bfe3fdc1ce79761fb8c9f49a6
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.database.sqlite; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 195a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Noriimport com.google.android.collect.Maps; 205a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2112311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnorimport android.app.ActivityThread; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.DatabaseUtils; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Debug; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 2890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikovimport android.os.SystemProperties; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Config; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog; 3290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikovimport android.util.Log; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 355a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Noriimport java.text.SimpleDateFormat; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 4012311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnorimport java.util.Random; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.WeakHashMap; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.locks.ReentrantLock; 44d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrickimport java.util.regex.Pattern; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Exposes methods to manage a SQLite database. 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * perform other common database management tasks. 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>See the Notepad sample application in the SDK for an example of creating 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and managing a database. 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> Database names must be unique within an application, not across all 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * applications. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <h3>Localized Collation - ORDER BY</h3> 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * two more, <code>LOCALIZED</code>, which changes with the system's current locale 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is the Unicode Collation Algorithm and not tailored to the current locale. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SQLiteDatabase extends SQLiteClosable { 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "Database"; 63082c2af6859dff103e781b372dfde927cc0f869fJeff Hamilton private static final int EVENT_DB_OPERATION = 52000; 64082c2af6859dff103e781b372dfde927cc0f869fJeff Hamilton private static final int EVENT_DB_CORRUPT = 75004; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Algorithms used in ON CONFLICT clause 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.sqlite.org/lang_conflict.html 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 708d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 718d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, an immediate ROLLBACK occurs, 728d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * thus ending the current transaction, and the command aborts with a 738d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * return code of SQLITE_CONSTRAINT. If no transaction is active 748d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * (other than the implied transaction that is created on every command) 758d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * then this algorithm works the same as ABORT. 768d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 778d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_ROLLBACK = 1; 78600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 798d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 808d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs,no ROLLBACK is executed 818d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * so changes from prior commands within the same transaction 828d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are preserved. This is the default behavior. 838d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 848d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_ABORT = 2; 85600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 868d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 878d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, the command aborts with a return 888d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * code SQLITE_CONSTRAINT. But any changes to the database that 898d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * the command made prior to encountering the constraint violation 908d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are preserved and are not backed out. 918d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 928d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_FAIL = 3; 93600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 948d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 958d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, the one row that contains 968d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * the constraint violation is not inserted or changed. 978d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * But the command continues executing normally. Other rows before and 988d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * after the row that contained the constraint violation continue to be 998d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * inserted or updated normally. No error is returned. 1008d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1018d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_IGNORE = 4; 102600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1038d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 1048d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a UNIQUE constraint violation occurs, the pre-existing rows that 1058d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are causing the constraint violation are removed prior to inserting 1068d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * or updating the current row. Thus the insert or update always occurs. 1078d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * The command continues executing normally. No error is returned. 1088d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * If a NOT NULL constraint violation occurs, the NULL value is replaced 1098d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * by the default value for that column. If the column has no default 1108d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * value, then the ABORT algorithm is used. If a CHECK constraint 1118d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * violation occurs then the IGNORE algorithm is used. When this conflict 1128d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * resolution strategy deletes rows in order to satisfy a constraint, 1138d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * it does not invoke delete triggers on those rows. 1148d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * This behavior might change in a future release. 1158d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1168d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_REPLACE = 5; 1176eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori 1188d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 1198d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * use the following when no conflict action is specified. 1208d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1218d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_NONE = 0; 1228d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori private static final String[] CONFLICT_VALUES = new String[] 1238d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "}; 124600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Maximum Length Of A LIKE Or GLOB Pattern 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern matching algorithm used in the default LIKE and GLOB implementation 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of SQLite can exhibit O(N^2) performance (where N is the number of characters in 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the pattern) for certain pathological cases. To avoid denial-of-service attacks 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes. 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The default value of this limit is 50000. A modern workstation can evaluate 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly. 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The denial of service problem only comes into play when the pattern length gets 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are at most a few dozen bytes in length, paranoid application developers may 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * want to reduce this parameter to something in the range of a few hundred 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if they know that external users are able to generate arbitrary patterns. 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database for reading and writing. 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If the disk is full, this may fail even before you actually write anything. 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@more} Note that the value of this flag is 0, so it is the default. 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int OPEN_READWRITE = 0x00000000; // update native code if changing 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database for reading only. 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the only reliable way to open a database if the disk may be full. 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int OPEN_READONLY = 0x00000001; // update native code if changing 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database without support for localized collators. 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@more} This causes the collator <code>LOCALIZED</code> not to be created. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You must be consistent when using this flag to use the setting the database was 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * created with. If this is set, {@link #setLocale} will do nothing. 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to create the database file if it does not already exist. 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Indicates whether the most-recently started transaction has been marked as successful. 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInnerTransactionIsSuccessful; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Valid during the life of a transaction, and indicates whether the entire transaction (the 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * outer one and all of the inner ones) so far has been successful. 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mTransactionIsSuccessful; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 182c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana /** 183c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * Valid during the life of a transaction. 184c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana */ 185c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana private SQLiteTransactionListener mTransactionListener; 186c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Synchronize on this when accessing the database */ 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final ReentrantLock mLock = new ReentrantLock(true); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredWallTime = 0L; 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredThreadTime = 0L; 192600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // limit the frequency of complaints about each database to one within 20 sec 194600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // unless run command adb shell setprop log.tag.Database VERBOSE 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_WARNING_WINDOW_IN_MS = 20000; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the lock is held this long then a warning will be printed when it is released. */ 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 201b43b58d3494426eda6117101635de25bb43efc20Dmitri Plotnikov private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000; 202600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 203d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // The pattern we remove from database filenames before 204d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // potentially logging them. 205d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private static final Pattern EMAIL_IN_DB_PATTERN = Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+"); 206d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastLockMessageTime = 0L; 208600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 209b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Things related to query logging/sampling for debugging 210b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // slow/frequent queries during development. Always log queries 211b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // which take 100ms+; shorter queries are sampled accordingly. 212b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Commit statements, which are typically slow, are logged 213b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // together with the most recently executed SQL statement, for 214b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // disambiguation. 215d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick private static final int QUERY_LOG_TIME_IN_MILLIS = 100; 21612311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private static final int QUERY_LOG_SQL_LENGTH = 64; 217b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private static final String COMMIT_SQL = "COMMIT;"; 21812311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private final Random mRandom = new Random(); 219b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private String mLastSqlStatement = null; 22012311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used by native code, do not rename */ 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ int mNativeHandle = 0; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used to make temp table names unique */ 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ int mTempTableSequence = 0; 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The path for the database file */ 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mPath; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 230d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** The anonymized path for the database file for logging purposes */ 231d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String mPathForLogs = null; // lazily populated 232d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The flags passed to open/create */ 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mFlags; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The optional factory to use when creating new Cursors */ 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CursorFactory mFactory; 238600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private WeakHashMap<SQLiteClosable, Object> mPrograms; 240600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2415a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 2425a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * for each instance of this class, a cache is maintained to store 2435a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * the compiled query statement ids returned by sqlite database. 2445a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * key = sql statement with "?" for bind args 2455a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * value = {@link SQLiteCompiledSql} 2465a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * If an application opens the database and keeps it open during its entire life, then 2475a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * there will not be an overhead of compilation of sql statements by sqlite. 2485a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * 2495a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * why is this cache NOT static? because sqlite attaches compiledsql statements to the 2505a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is 2515a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * invoked. 2525a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * 2535a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method 2545a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * (@link setMaxCacheSize(int)}). its default is 0 - i.e., no caching by default because 2555a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * most of the apps don't use "?" syntax in their sql, caching is not useful for them. 2565a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 257e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap(); 258e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 259e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 260e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 261e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public static final int MAX_SQL_CACHE_SIZE = 250; 262e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori private int mMaxSqlCacheSize = MAX_SQL_CACHE_SIZE; // max cache size per Database instance 263e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori private int mCacheFullWarnings; 264e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 5; 2655a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2665a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** maintain stats about number of cache hits and misses */ 2675a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private int mNumCacheHits; 2685a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private int mNumCacheMisses; 2695a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2705a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** the following 2 members maintain the time when a database is opened and closed */ 2715a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private String mTimeOpened = null; 2725a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private String mTimeClosed = null; 2735a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final RuntimeException mLeakedException; 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov // System property that enables logging of slow queries. Specify the threshold in ms. 27790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold"; 27890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private final int mSlowQueryThreshold; 27990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param closable 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void addSQLiteClosable(SQLiteClosable closable) { 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms.put(closable, null); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 291600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void removeSQLiteClosable(SQLiteClosable closable) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms.remove(closable); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 299600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 300600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onAllReferencesReleased() { 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpen()) { 3045a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 3055a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mTimeClosed = getTime(); 3065a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbclose(); 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attempts to release memory that SQLite holds but does not require to 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * operate properly. Typically this memory will come from the page cache. 314600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of bytes actually released 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 317600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov static public native int releaseMemory(); 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Control whether or not the SQLiteDatabase is made thread-safe by using locks 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections. This is pretty expensive, so if you know that your 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * DB will only be used by a single thread then you should set this to false. 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The default is true. 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param lockingEnabled set to true to enable locks, false otherwise 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setLockingEnabled(boolean lockingEnabled) { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockingEnabled = lockingEnabled; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If set then the SQLiteDatabase is made thread-safe by using locks 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mLockingEnabled = true; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void onCorruption() { 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Close the database (if we can), which will cause subsequent operations to fail. 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project close(); 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Removing corrupt database: " + mPath); 342dd1b39be1e077d19911e8dc7bf00db0e31b63287Vasu Nori EventLog.writeEvent(EVENT_DB_CORRUPT, mPath); 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Delete the corrupt file. Don't re-create it now -- that would just confuse people 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // -- but the next time someone tries to open it, they can set it up from scratch. 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new File(mPath).delete(); 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. This is a no-op if mLockingEnabled is false. 354600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void lock() { 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void lockForced() { 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. This is a no-op if mLockingEnabled is false. 390600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void unlock() { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void unlockForced() { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkLockHoldTime() { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long elapsedTime = SystemClock.elapsedRealtime(); 420600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long lockedTime = elapsedTime - mLockAcquiredWallTime; 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT && 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !Log.isLoggable(TAG, Log.VERBOSE) && 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) { 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int threadTime = (int) 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS || 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) { 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastLockMessageTime = elapsedTime; 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was " 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + threadTime + "ms"; 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) { 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg, new Exception()); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the work done in that transaction and all of the nested transactions will be committed or 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rolled back. The changes will be rolled back if any transaction is ended without being 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Here is the standard idiom for transactions: 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.beginTransaction(); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * try { 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ... 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.setTransactionSuccessful(); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } finally { 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.endTransaction(); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre> 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void beginTransaction() { 462c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana beginTransactionWithListener(null /* transactionStatusCallback */); 463c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 464c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana 465c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana /** 466c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of 467c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * the work done in that transaction and all of the nested transactions will be committed or 468c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * rolled back. The changes will be rolled back if any transaction is ended without being 469c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 470c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * 471c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <p>Here is the standard idiom for transactions: 472c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * 473c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <pre> 474c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.beginTransactionWithListener(listener); 475c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * try { 476c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * ... 477c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.setTransactionSuccessful(); 478c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } finally { 479c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.endTransaction(); 480c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } 481c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * </pre> 482c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * @param transactionListener listener that should be notified when the transaction begins, 483c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * commits, or is rolled back, either explicitly or by a call to 484c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * {@link #yieldIfContendedSafely}. 485c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana */ 486c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) { 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lockForced(); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean ok = false; 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this thread already had the lock then get out 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() > 1) { 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "Cannot call beginTransaction between " 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "calling setTransactionSuccessful and endTransaction"; 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IllegalStateException e = new IllegalStateException(msg); 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "beginTransaction() failed", e); 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This thread didn't already have the lock, so begin a database 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // transaction now. 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("BEGIN EXCLUSIVE;"); 506c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = transactionListener; 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = true; 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 509c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (transactionListener != null) { 510c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 511c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana transactionListener.onBegin(); 512c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 513c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana execSQL("ROLLBACK;"); 514c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw e; 515c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 516c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!ok) { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // beginTransaction is called before the try block so we must release the lock in 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the case of failure. 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * End a transaction. See beginTransaction for notes about how to use this and when transactions 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are committed and rolled back. 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void endTransaction() { 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLock.isHeldByCurrentThread()) { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("no transaction pending"); 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = false; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() != 1) { 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 544c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana RuntimeException savedException = null; 545c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionListener != null) { 546c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 547c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionIsSuccessful) { 548c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onCommit(); 549c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } else { 550c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onRollback(); 551c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 552c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 553c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana savedException = e; 554c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionIsSuccessful = false; 555c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 556c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTransactionIsSuccessful) { 558b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick execSQL(COMMIT_SQL); 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("ROLLBACK;"); 562c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (savedException != null) { 563c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw savedException; 564c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD) { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "exception during rollback, maybe the DB previously " 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "performed an auto-rollback"); 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 573c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = null; 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGV) { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "unlocked " + Thread.currentThread() 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ", holdCount is " + mLock.getHoldCount()); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Marks the current transaction as successful. Do not do any more database work between 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * calling this and calling endTransaction. Do as little non-database work as possible in that 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * situation too. If any errors are encountered between this and endTransaction the transaction 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will still be committed. 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IllegalStateException if the current thread is not in a transaction or the 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * transaction is already marked as successful. 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTransactionSuccessful() { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLock.isHeldByCurrentThread()) { 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("no transaction pending"); 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "setTransactionSuccessful may only be called once per call to beginTransaction"); 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = true; 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return true if there is a transaction pending 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean inTransaction() { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLock.getHoldCount() > 0; 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database lock is held by this thread. 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if this thread is holding the database lock. 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByCurrentThread() { 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLock.isHeldByCurrentThread(); 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database is locked by another thread. This is 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * just an estimate, since this status can change at any time, 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * including after the call is made but before the result has 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * been acted upon. 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if the database is locked by another thread 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByOtherThreads() { 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !mLock.isHeldByCurrentThread() && mLock.isLocked(); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will not be yielded. Use yieldIfContendedSafely instead. 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6384a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn @Deprecated 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContended() { 6405c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(false /* do not check yielding */, 6415c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana -1 /* sleepAfterYieldDelay */); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. This assumes 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that there are no nested transactions (beginTransaction has only been called once) and will 6495c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContendedSafely() { 6535c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/); 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6565c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana /** 6575c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * Temporarily end the transaction to let other threads run. The transaction is assumed to be 6585c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * successful so far. Do not call setTransactionSuccessful before calling this. When this 6595c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * returns a new transaction will have been created but not marked as successful. This assumes 6605c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * that there are no nested transactions (beginTransaction has only been called once) and will 6615c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 6625c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if 6635c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * the lock was actually yielded. This will allow other background threads to make some 6645c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * more progress than they would if we started the transaction immediately. 6655c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @return true if the transaction was yielded 6665c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana */ 6675c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) { 6685c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay); 6695c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 6705c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana 6715c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) { 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getQueueLength() == 0) { 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset the lock acquire time since we know that the thread was willing to yield 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the lock at this time. 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setTransactionSuccessful(); 680c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana SQLiteTransactionListener transactionListener = mTransactionListener; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project endTransaction(); 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (checkFullyYielded) { 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (this.isDbLockedByCurrentThread()) { 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Db locked more than once. yielfIfContended cannot yield"); 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6885c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana if (sleepAfterYieldDelay > 0) { 689600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to 690600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // check if anyone is using the database. If the database is not contended, 691600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // retake the lock and return. 692600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long remainingDelay = sleepAfterYieldDelay; 693600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov while (remainingDelay > 0) { 694600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov try { 695600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ? 696600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay : SLEEP_AFTER_YIELD_QUANTUM); 697600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } catch (InterruptedException e) { 698600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.interrupted(); 699600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 700600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM; 701600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov if (mLock.getQueueLength() == 0) { 702600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov break; 703600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 7045c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 7055c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 706c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana beginTransactionWithListener(transactionListener); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Maps table names to info about what to which _sync_time column to set 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to NULL on an update. This is used to support syncing. */ 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Map<String, SyncUpdateInfo> mSyncUpdateInfo = 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new HashMap<String, SyncUpdateInfo>(); 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Map<String, String> getSyncedTables() { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(mSyncUpdateInfo) { 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HashMap<String, String> tables = new HashMap<String, String>(); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String table : mSyncUpdateInfo.keySet()) { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info = mSyncUpdateInfo.get(table); 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (info.deletedTable != null) { 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tables.put(table, info.deletedTable); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Internal class used to keep track what needs to be marked as changed 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when an update occurs. This is used for syncing, so the sync engine 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * knows what data has been updated locally. 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private class SyncUpdateInfo { 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates the SyncUpdateInfo class. 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param masterTable The table to set _sync_time to NULL in 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * master table 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey The key that refers to the primary key in table 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo(String masterTable, String deletedTable, 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String foreignKey) { 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.masterTable = masterTable; 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.deletedTable = deletedTable; 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.foreignKey = foreignKey; 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The table containing the _sync_time column */ 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String masterTable; 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The deleted table that corresponds to the master table */ 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String deletedTable; 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The key in the local table the row in table. It may be _id, if table 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is the local table. */ 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String foreignKey; 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Used to allow returning sub-classes of {@link Cursor} when calling query. 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface CursorFactory { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver, 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * String, SQLiteQuery)}. 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor newCursor(SQLiteDatabase db, 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursorDriver masterQuery, String editTable, 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteQuery query); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Open the database according to the flags {@link #OPEN_READWRITE} 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path to database file to open and/or create 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called, or null for default 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags to control database access mode 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the newly opened database 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLiteException if the database cannot be opened 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteDatabase db = null; 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Open the database. 7923ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags); 7933ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 7943ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori sqliteDatabase.enableSqlTracing(path); 7953ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori } 7963ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori if (SQLiteDebug.DEBUG_SQL_TIME) { 7973ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori sqliteDatabase.enableSqlProfiling(path); 7983ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori } 7993ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori return sqliteDatabase; 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try to recover from this, if we can. 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: should we do this for other open failures? 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Deleting and re-creating corrupt database " + path, e); 804082c2af6859dff103e781b372dfde927cc0f869fJeff Hamilton EventLog.writeEvent(EVENT_DB_CORRUPT, path); 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new File(path).delete(); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SQLiteDatabase(path, factory, flags); 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY). 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) { 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openOrCreateDatabase(file.getPath(), factory); 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY). 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) { 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openDatabase(path, factory, CREATE_IF_NECESSARY); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a memory backed SQLite database. Its contents will be destroyed 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the database is closed. 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a SQLiteDatabase object, or null if the database can't be created 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase create(CursorFactory factory) { 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is a magic string with special meaning for SQLite. 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openDatabase(":memory:", factory, CREATE_IF_NECESSARY); 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Close the database. 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void close() { 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeClosable(); 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project releaseReference(); 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void closeClosable() { 854e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* deallocate all compiled sql statement objects from mCompiledQueries cache. 855e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * this should be done before de-referencing all {@link SQLiteClosable} objects 856e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * from this database object because calling 857e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database 858e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * to be closed. sqlite doesn't let a database close if there are 859e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries. 860e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 861e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori deallocCachedSqlStatements(); 862e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator(); 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iter.hasNext()) { 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<SQLiteClosable, Object> entry = iter.next(); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteClosable program = entry.getKey(); 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (program != null) { 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project program.onAllReferencesReleasedFromContainer(); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 870600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 872600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to close the database. 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbclose(); 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the database version. 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database version 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getVersion() { 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement prog = null; 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prog = new SQLiteStatement(this, "PRAGMA user_version;"); 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long version = prog.simpleQueryForLong(); 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (int) version; 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prog != null) prog.close(); 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database version. 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param version the new database version 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVersion(int version) { 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA user_version = " + version); 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the maximum size the database may grow to. 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getMaximumSize() { 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement prog = null; 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prog = new SQLiteStatement(this, 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "PRAGMA max_page_count;"); 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long pageCount = prog.simpleQueryForLong(); 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pageCount * getPageSize(); 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prog != null) prog.close(); 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the maximum size the database will grow to. The maximum size cannot 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be set below the current size. 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the maximum database size, in bytes 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long setMaximumSize(long numBytes) { 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement prog = null; 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long pageSize = getPageSize(); 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long numPages = numBytes / pageSize; 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If numBytes isn't a multiple of pageSize, bump up a page 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((numBytes % pageSize) != 0) { 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numPages++; 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prog = new SQLiteStatement(this, 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "PRAGMA max_page_count = " + numPages); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long newPageCount = prog.simpleQueryForLong(); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return newPageCount * pageSize; 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prog != null) prog.close(); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the current database page size, in bytes. 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database page size, in bytes 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getPageSize() { 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement prog = null; 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prog = new SQLiteStatement(this, 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "PRAGMA page_size;"); 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long size = prog.simpleQueryForLong(); 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return size; 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prog != null) prog.close(); 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database page size. The page size must be a power of two. This 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method does not work if any data has been written to the database file, 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and must be called right after the database has been created. 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the database page size, in bytes 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPageSize(long numBytes) { 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA page_size = " + numBytes); 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable. When an update occurs in this table the 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * _sync_dirty field will be set to ensure proper syncing operation. 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to mark as syncable 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * syncable table 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void markTableSyncable(String table, String deletedTable) { 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project markTableSyncable(table, "_id", table, deletedTable); 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable, with the _sync_dirty residing in another 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * table. When an update occurs in this table the _sync_dirty field of the 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row in updateTable with the _id in foreignKey will be set to 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ensure proper syncing operation. 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table an update on this table will trigger a sync time removal 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey this is the column in table whose value is an _id in 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param updateTable this is the table that will have its _sync_dirty 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void markTableSyncable(String table, String foreignKey, 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String updateTable) { 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project markTableSyncable(table, foreignKey, updateTable, null); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable, with the _sync_dirty residing in another 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * table. When an update occurs in this table the _sync_dirty field of the 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row in updateTable with the _id in foreignKey will be set to 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ensure proper syncing operation. 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table an update on this table will trigger a sync time removal 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey this is the column in table whose value is an _id in 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param updateTable this is the table that will have its _sync_dirty 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void markTableSyncable(String table, String foreignKey, 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String updateTable, String deletedTable) { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL("SELECT _sync_dirty FROM " + updateTable 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " LIMIT 0"); 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL("SELECT " + foreignKey + " FROM " + table 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " LIMIT 0"); 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable, 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foreignKey); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSyncUpdateInfo) { 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSyncUpdateInfo.put(table, info); 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call for each row that is updated in a cursor. 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table the row is in 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param rowId the row ID of the updated row 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void rowUpdated(String table, long rowId) { 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info; 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSyncUpdateInfo) { 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info = mSyncUpdateInfo.get(table); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (info != null) { 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("UPDATE " + info.masterTable 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " FROM " + table + " WHERE _id=" + rowId + ")"); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Finds the name of the first table, which is editable. 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tables a list of tables 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the first table listed 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String findEditTable(String tables) { 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(tables)) { 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // find the first word terminated by either a space or a comma 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spacepos = tables.indexOf(' '); 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int commapos = tables.indexOf(','); 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spacepos > 0 && (spacepos < commapos || commapos < 0)) { 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, spacepos); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) { 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, commapos); 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("Invalid tables"); 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compiles an SQL statement into a reusable pre-compiled statement object. 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement and fill in those values with {@link SQLiteProgram#bindString} 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and {@link SQLiteProgram#bindLong} each time you want to run the 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement. Statements may not return result sets larger than 1x1. 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql The raw SQL statement, may contain ? for unknown values to be 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bound later. 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a pre-compiled statement object. 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SQLiteStatement compileStatement(String sql) throws SQLException { 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SQLiteStatement(this, sql); 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A Cursor object, which is positioned before the first entry 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(boolean distinct, String table, String[] columns, 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return queryWithFactory(null, distinct, table, columns, selection, selectionArgs, 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupBy, having, orderBy, limit); 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A Cursor object, which is positioned before the first entry 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor queryWithFactory(CursorFactory cursorFactory, 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean distinct, String table, String[] columns, 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String sql = SQLiteQueryBuilder.buildQueryString( 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project distinct, table, columns, selection, groupBy, having, orderBy, limit); 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory( 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory, sql, selectionArgs, findEditTable(table)); 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A {@link Cursor} object, which is positioned before the first entry 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy) { 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, null /* limit */); 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A {@link Cursor} object, which is positioned before the first entry 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy, String limit) { 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, limit); 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a {@link Cursor} over the result set. 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A {@link Cursor} object, which is positioned before the first entry 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQuery(String sql, String[] selectionArgs) { 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory(null, sql, selectionArgs, null); 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param editTable the name of the first table, which is editable 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A {@link Cursor} object, which is positioned before the first entry 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQueryWithFactory( 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CursorFactory cursorFactory, String sql, String[] selectionArgs, 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String editTable) { 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long timeStart = 0; 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 128290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timeStart = System.currentTimeMillis(); 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable); 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 128890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Cursor cursor = null; 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 129090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov cursor = driver.query( 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory != null ? cursorFactory : mFactory, 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectionArgs); 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 129490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 129590142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 129690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov // Force query execution 129790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (cursor != null) { 129890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov cursor.moveToFirst(); 129990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov cursor.moveToPosition(-1); 130090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov } 130190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long duration = System.currentTimeMillis() - timeStart; 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 130490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || duration >= mSlowQueryThreshold) { 130590142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Log.v(SQLiteCursor.TAG, 130690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov "query (" + duration + " ms): " + driver.toString() + ", args are " 130790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov + (selectionArgs != null 130890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov ? TextUtils.join(",", selectionArgs) 130990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov : "<null>")); 131090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov } 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 131390142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov return cursor; 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 1318600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * The cursor will read an initial set of rows and the return to the caller. 1319600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * It will continue to read in batches and send data changed notifications 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the later batches are ready. 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialRead set the initial count of items to read from the cursor 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxRead set the count of items to read on each iteration after the first 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A {@link Cursor} object, which is positioned before the first entry 1328600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 1329f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * This work is incomplete and not fully tested or reviewed, so currently 1330f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * hidden. 1331f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * @hide 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1333600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public Cursor rawQuery(String sql, String[] selectionArgs, 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int initialRead, int maxRead) { 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, sql, selectionArgs, null); 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.setLoadStyle(initialRead, maxRead); 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return c; 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1340600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insert(String table, String nullColumnHack, ContentValues values) { 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13558d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + values, e); 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertOrThrow(String table, String nullColumnHack, ContentValues values) 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws SQLException { 13778d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replace(String table, String nullColumnHack, ContentValues initialValues) { 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1393600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 13948d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + initialValues, e); 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replaceOrThrow(String table, String nullColumnHack, 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues initialValues) throws SQLException { 1415600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 14168d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * General method for inserting a row into the database. 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for the 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 14298d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for insert conflict resolver 14306eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * @return the row ID of the newly inserted row 14316eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR the primary key of the existing row if the input param 'conflictAlgorithm' = 14328d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * {@link #CONFLICT_IGNORE} 14336eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR -1 if any error 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertWithOnConflict(String table, String nullColumnHack, 14366eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori ContentValues initialValues, int conflictAlgorithm) { 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isOpen()) { 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("database not open"); 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Measurements show most sql lengths <= 152 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sql = new StringBuilder(152); 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("INSERT"); 14448d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" INTO "); 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Measurements show most values lengths < 40 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder values = new StringBuilder(40); 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Set<Map.Entry<String, Object>> entrySet = null; 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (initialValues != null && initialValues.size() > 0) { 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entrySet = initialValues.valueSet(); 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append('('); 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needSeparator = false; 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (entriesIter.hasNext()) { 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needSeparator) { 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(", "); 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append(", "); 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project needSeparator = true; 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(entry.getKey()); 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append('?'); 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(')'); 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("(" + nullColumnHack + ") "); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append("NULL"); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" VALUES("); 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(values); 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(");"); 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql.toString()); 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bind the values 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entrySet != null) { 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = entrySet.size(); 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue()); 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Run the program and then cleanup 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long insertedRowId = lastInsertRow(); 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (insertedRowId == -1) { 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + initialValues + " using " + sql); 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "Inserting row " + insertedRowId + " from " 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + initialValues + " using " + sql); 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return insertedRowId; 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for deleting rows in the database. 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to delete from 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when deleting. 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will delete all rows. 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected if a whereClause is passed in, 0 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * otherwise. To remove all rows and get a count pass "1" as the 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * whereClause. 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int delete(String table, String whereClause, String[] whereArgs) { 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isOpen()) { 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("database not open"); 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement("DELETE FROM " + table 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (!TextUtils.isEmpty(whereClause) 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? " WHERE " + whereClause : "")); 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (whereArgs != null) { 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numArgs = whereArgs.length; 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numArgs; i++) { 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]); 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return lastChangeCount(); 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { 15688d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE); 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1570600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 15798d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for update conflict resolver 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1582600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public int updateWithOnConflict(String table, ContentValues values, 15836eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori String whereClause, String[] whereArgs, int conflictAlgorithm) { 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isOpen()) { 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("database not open"); 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (values == null || values.size() == 0) { 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty values"); 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sql = new StringBuilder(120); 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("UPDATE "); 15948d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" SET "); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Set<Map.Entry<String, Object>> entrySet = values.valueSet(); 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (entriesIter.hasNext()) { 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(entry.getKey()); 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("=?"); 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entriesIter.hasNext()) { 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(", "); 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(whereClause)) { 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" WHERE "); 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(whereClause); 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql.toString()); 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bind the values 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = entrySet.size(); 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entriesIter = entrySet.iterator(); 16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bindArg = 1; 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue()); 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bindArg++; 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (whereArgs != null) { 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size = whereArgs.length; 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.bindString(bindArg, whereArgs[i]); 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bindArg++; 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Run the program and then cleanup 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numChangedRows = lastChangeCount(); 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql); 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return numChangedRows; 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error updating " + values + " using " + sql); 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Execute a single SQL statement that is not a query. For example, CREATE 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * supported. it takes a write lock 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void execSQL(String sql) throws SQLException { 1668d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long timeStart = SystemClock.uptimeMillis(); 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL(sql); 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1678b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1679b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Log commit statements along with the most recently executed 1680b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // SQL statement for disambiguation. Note that instance 1681b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // equality to COMMIT_SQL is safe here. 1682b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick if (sql == COMMIT_SQL) { 1683b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick logTimeStat(sql + mLastSqlStatement, timeStart); 1684b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } else { 1685b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick logTimeStat(sql, timeStart); 1686b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Execute a single SQL statement that is not a query. For example, CREATE 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * supported. it takes a write lock, 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bindArgs only byte[], String, Long and Double are supported in bindArgs. 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void execSQL(String sql, Object[] bindArgs) throws SQLException { 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bindArgs == null) { 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty bindArgs"); 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1702d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long timeStart = SystemClock.uptimeMillis(); 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql); 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bindArgs != null) { 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numArgs = bindArgs.length; 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numArgs; i++) { 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]); 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 172312311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor logTimeStat(sql, timeStart); 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() { 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpen()) { 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPrograms.isEmpty()) { 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Leak found", mLeakedException); 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IllegalStateException leakProgram = new IllegalStateException( 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "mPrograms size " + mPrograms.size(), mLeakedException); 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Leak found", leakProgram); 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeClosable(); 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onAllReferencesReleased(); 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Private constructor. See {@link #create} and {@link #openDatabase}. 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory The factory to use when creating cursors, may be NULL. 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * exists, mFlags will be updated appropriately. 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SQLiteDatabase(String path, CursorFactory factory, int flags) { 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null) { 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("path should not be null"); 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFlags = flags; 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 175590142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1); 1756600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeakedException = new IllegalStateException(path + 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " SQLiteDatabase created and never closed"); 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFactory = factory; 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbopen(mPath, mFlags); 17615a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 17625a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mTimeOpened = getTime(); 17635a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms = new WeakHashMap<SQLiteClosable,Object>(); 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setLocale(Locale.getDefault()); 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e) { 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e); 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbclose(); 17705a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 17715a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mTimeClosed = getTime(); 17725a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17775a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private String getTime() { 17785a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis()); 17795a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 17805a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return whether the DB is opened as read only. 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if DB is opened as read only 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isReadOnly() { 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mFlags & OPEN_READ_MASK) == OPEN_READONLY; 17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the DB is currently open (has not been closed) 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isOpen() { 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mNativeHandle != 0; 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean needUpgrade(int newVersion) { 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return newVersion > getVersion(); 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Getter for the path to the database file. 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the path to our database file. 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final String getPath() { 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPath; 18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1810e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1811d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick /* package */ void logTimeStat(String sql, long beginMillis) { 1812b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Keep track of the last statement executed here, as this is 1813b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // the common funnel through which all methods of hitting 1814b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // libsqlite eventually flow. 1815b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick mLastSqlStatement = sql; 1816b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1817e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sample fast queries in proportion to the time taken. 1818e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Quantize the % first, so the logged sampling probability 1819e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // exactly equals the actual sampling rate for this query. 1820e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1821e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori int samplePercent; 1822d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long durationMillis = SystemClock.uptimeMillis() - beginMillis; 1823d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick if (durationMillis >= QUERY_LOG_TIME_IN_MILLIS) { 1824e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori samplePercent = 100; 1825e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } else { 1826d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick samplePercent = (int) (100 * durationMillis / QUERY_LOG_TIME_IN_MILLIS) + 1; 1827e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (mRandom.nextInt(100) >= samplePercent) return; 18285a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 1829e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1830e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH); 1831e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1832e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // ActivityThread.currentPackageName() only returns non-null if the 1833e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // current thread is an application main thread. This parameter tells 1834e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // us whether an event loop is blocked, and if so, which app it is. 1835e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // 1836e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sadly, there's no fast way to determine app name if this is *not* a 1837e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // main thread, or when we are invoked via Binder (e.g. ContentProvider). 1838e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Hopefully the full path to the database will be informative enough. 1839e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1840e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori String blockingPackage = ActivityThread.currentPackageName(); 1841e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (blockingPackage == null) blockingPackage = ""; 1842e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1843d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick EventLog.writeEvent( 1844d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick EVENT_DB_OPERATION, 1845d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick getPathForLogs(), 1846d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick sql, 1847d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick durationMillis, 1848d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick blockingPackage, 1849d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick samplePercent); 1850d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1851d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 1852d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** 1853d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * Removes email addresses from database filenames before they're 1854d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * logged to the EventLog where otherwise apps could potentially 1855d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * read them. 1856d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick */ 1857d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String getPathForLogs() { 1858d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPathForLogs != null) { 1859d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 1860d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1861d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath == null) { 1862d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return null; 1863d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1864d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath.indexOf('@') == -1) { 1865d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = mPath; 1866d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } else { 1867d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = EMAIL_IN_DB_PATTERN.matcher(mPath).replaceAll("XX@YY"); 1868d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1869d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 18705a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 18715a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 18725a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 1873e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * Sets the locale for this database. Does nothing if this database has 1874e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * the NO_LOCALIZED_COLLATORS flag set or was opened read only. 1875e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @throws SQLException if the locale could not be set. The most common reason 1876e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * for this is that there is no collator available for the locale you requested. 1877e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * In this case the database remains unchanged. 18785a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 1879e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public void setLocale(Locale locale) { 1880e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori lock(); 1881e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori try { 1882e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori native_setLocale(locale.toString(), mFlags); 1883e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } finally { 1884e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori unlock(); 18855a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 18865a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 18875a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 1888e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* 1889e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * ============================================================================ 1890e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 1891e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * The following methods deal with compiled-sql cache 1892e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * ============================================================================ 1893e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 18945a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 18955a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * adds the given sql and its compiled-statement-id-returned-by-sqlite to the 18965a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * cache of compiledQueries attached to 'this'. 18975a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * 18985a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * if there is already a {@link SQLiteCompiledSql} in compiledQueries for the given sql, 18995a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current 19005a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * mapping is NOT replaced with the new mapping). 19015a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 1902e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) { 19035a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (mMaxSqlCacheSize == 0) { 19045a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori // for this database, there is no cache of compiled sql. 19055a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 19065a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori Log.v(TAG, "|NOT adding_sql_to_cache|" + getPath() + "|" + sql); 19075a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 1908e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return; 19095a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19105a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 1911994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori /* don't cache PRAGMA sql statements. 1912994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori * caching them makes sqlite return incorrect results on pragma sql execution! 1913994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori */ 1914994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori String prefixSql = sql.substring(0, 6); 1915994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori if (prefixSql.toLowerCase().startsWith("pragma")) { 1916994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori return; 1917994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori } 1918994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori 19195a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori SQLiteCompiledSql compiledSql = null; 19205a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori synchronized(mCompiledQueries) { 19215a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori // don't insert the new mapping if a mapping already exists 19225a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori compiledSql = mCompiledQueries.get(sql); 19235a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (compiledSql != null) { 1924e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return; 19255a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19265a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori // add this <sql, compiledStatement> to the cache 19275a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (mCompiledQueries.size() == mMaxSqlCacheSize) { 19285a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /* reached max cachesize. before adding new entry, remove an entry from the 19295a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * cache. we don't want to wipe out the entire cache because of this: 19305a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * GCing {@link SQLiteCompiledSql} requires call to sqlite3_finalize 1931e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * JNI method. If entire cache is wiped out, it could cause a big GC activity 19325a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * just because a (rogue) process is using the cache incorrectly. 19335a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 1934e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " + 1935e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori getPath() + "; i.e., NO space for this sql statement in cache: " + 193682f82be4b3f97cd8a1fd298d8389f5dc54fea01dVasu Nori sql + ". Please change your sql statements to use '?' for " + 1937e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori "bindargs, instead of using actual values"); 1938e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori 1939e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori /* increment the number of times this warnings has been printed. 1940e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori * if this warning is printed too many times, clear the whole cache - the app 1941e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori * is doing something weird or incorrect and printing more warnings will only 1942e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori * flood the logfile. 1943e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori */ 1944e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori if (++mCacheFullWarnings > MAX_WARNINGS_ON_CACHESIZE_CONDITION) { 1945e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori mCacheFullWarnings = 0; 1946e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori // clear the cache 1947e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori mCompiledQueries.clear(); 1948adf1c58fa91c3051697a14e3c7cc8a47e5d1dd83Vasu Nori Log.w(TAG, "Compiled-sql statement cache for database: " + 1949adf1c58fa91c3051697a14e3c7cc8a47e5d1dd83Vasu Nori getPath() + " hit MAX size-limit too many times. " + 1950adf1c58fa91c3051697a14e3c7cc8a47e5d1dd83Vasu Nori "Removing all compiled-sql statements from the cache."); 1951e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori } else { 1952e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori // clear just a single entry from cache 1953e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori Set<String> keySet = mCompiledQueries.keySet(); 1954e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori for (String s : keySet) { 1955e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori mCompiledQueries.remove(s); 1956e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori break; 1957e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori } 19585a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19595a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 1960e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mCompiledQueries.put(sql, compiledStatement); 19615a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19625a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 19635a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" + mCompiledQueries.size() + "|" + 19645a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori sql); 19655a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 1966e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return; 1967e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 1968e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1969e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1970e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori private void deallocCachedSqlStatements() { 1971e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori synchronized (mCompiledQueries) { 1972e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) { 1973e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori compiledSql.releaseSqlStatement(); 1974e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 1975e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mCompiledQueries.clear(); 1976e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 19775a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19785a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 19795a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 19805a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * from the compiledQueries cache, returns the compiled-statement-id for the given sql. 19815a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * returns null, if not found in the cache. 19825a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 19835a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) { 1984994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori // don't look for PRAGMA sql statements in compiled-sql cache 1985994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori String prefixSql = sql.substring(0, 6); 1986994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori if (prefixSql.toLowerCase().startsWith("pragma")) { 1987994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori return null; 1988994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori } 1989994bc22f1e89efae7739c50c41fcf23c6e4847a6Vasu Nori 19905a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori SQLiteCompiledSql compiledStatement = null; 19915a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori boolean cacheHit; 19925a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori synchronized(mCompiledQueries) { 19935a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (mMaxSqlCacheSize == 0) { 19945a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori // for this database, there is no cache of compiled sql. 19955a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 19965a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori Log.v(TAG, "|cache NOT found|" + getPath()); 19975a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19985a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori return null; 19995a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20005a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null; 20015a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20025a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (cacheHit) { 20035a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mNumCacheHits++; 20045a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } else { 20055a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mNumCacheMisses++; 20065a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20075a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 20085a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 20095a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori Log.v(TAG, "|cache_stats|" + 20105a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori getPath() + "|" + mCompiledQueries.size() + 20115a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori "|" + mNumCacheHits + "|" + mNumCacheMisses + 20125a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori "|" + cacheHit + "|" + mTimeOpened + "|" + mTimeClosed + "|" + sql); 20135a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20145a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori return compiledStatement; 20155a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20165a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2017e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2018e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * returns true if the given sql is cached in compiled-sql cache. 2019e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 2020e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 2021e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public boolean isInCompiledSqlCache(String sql) { 2022e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori synchronized(mCompiledQueries) { 2023e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return mCompiledQueries.containsKey(sql); 202412311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor } 2025e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 202612311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 2027e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2028e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * purges the given sql from the compiled-sql cache. 2029e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 2030e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 2031e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public void purgeFromCompiledSqlCache(String sql) { 2032e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori synchronized(mCompiledQueries) { 2033e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mCompiledQueries.remove(sql); 2034e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 2035e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 203612311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 2037e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2038e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * remove everything from the compiled sql cache 2039e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 2040e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 2041e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public void resetCompiledSqlCache() { 2042e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori synchronized(mCompiledQueries) { 2043e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mCompiledQueries.clear(); 2044e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 2045e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 204612311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 2047e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2048e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * return the current maxCacheSqlCacheSize 2049e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 2050e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 2051e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public synchronized int getMaxSqlCacheSize() { 2052e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return mMaxSqlCacheSize; 20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2056e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * set the max size of the compiled sql cache for this database after purging the cache. 2057e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * (size of the cache = number of compiled-sql-statements stored in the cache). 2058e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 2059e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * max cache size can ONLY be increased from its current size (default = 0). 2060e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * if this method is called with smaller size than the current value of mMaxSqlCacheSize, 2061e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * then IllegalStateException is thrown 2062e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 2063e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * synchronized because we don't want t threads to change cache size at the same time. 2064e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @param cacheSize the size of the cache. can be (0 to MAX_SQL_CACHE_SIZE) 2065e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @throws IllegalStateException if input cacheSize > MAX_SQL_CACHE_SIZE or < 0 or 2066e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * < the value set with previous setMaxSqlCacheSize() call. 2067e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 2068e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @hide 20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2070e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public synchronized void setMaxSqlCacheSize(int cacheSize) { 2071e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) { 2072e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE); 2073e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } else if (cacheSize < mMaxSqlCacheSize) { 2074e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori throw new IllegalStateException("cannot set cacheSize to a value less than the value " + 2075e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori "set with previous setMaxSqlCacheSize() call."); 20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2077e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mMaxSqlCacheSize = cacheSize; 20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to open the database. 20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbopen(String path, int flags); 20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20883ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * Native call to setup tracing of all sql statements 20893ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 20903ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 20913ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 20923ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori private native void enableSqlTracing(String path); 20933ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 20943ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 20953ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * Native call to setup profiling of all sql statements. 20963ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * currently, sqlite's profiling = printing of execution-time 20973ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * (wall-clock time) of each of the sql statements, as they 20983ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * are executed. 20993ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 21003ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 21013ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 21023ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori private native void enableSqlProfiling(String path); 21033ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 21043ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to execute a raw SQL statement. {@link #lock} must be held 21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when calling this method. 21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql The raw SQL string 21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native void native_execSQL(String sql) throws SQLException; 21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to set the locale. {@link #lock} must be held when calling 21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this method. 21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native void native_setLocale(String loc, int flags); 21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the row ID of the last row inserted into the database. 21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the last row inserted into the database. 21249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native long lastInsertRow(); 21269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of changes made in the last statement executed. 21299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of changes made in the last statement executed. 21319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native int lastChangeCount(); 21339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2134