SQLiteDatabase.java revision 74f170f9468d3cf6d7d0ef453320141a3e63571b
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 1912311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnorimport android.app.ActivityThread; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 22062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Noriimport android.database.DatabaseErrorHandler; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.DatabaseUtils; 24062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Noriimport android.database.DefaultDatabaseErrorHandler; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException; 26c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport android.database.sqlite.SQLiteDebug.DbStats; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Debug; 28a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Noriimport android.os.StatFs; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 3090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikovimport android.os.SystemProperties; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Config; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog; 3490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikovimport android.util.Log; 35c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport android.util.Pair; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 38c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport java.lang.ref.WeakReference; 39c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport java.util.ArrayList; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 41c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport java.util.HashSet; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 4320f549fd2f40db524242c9038d7d63356adf95fcVasu Noriimport java.util.LinkedHashMap; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 4612311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnorimport java.util.Random; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.WeakHashMap; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.locks.ReentrantLock; 50d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrickimport java.util.regex.Pattern; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Exposes methods to manage a SQLite database. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * perform other common database management tasks. 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>See the Notepad sample application in the SDK for an example of creating 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and managing a database. 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> Database names must be unique within an application, not across all 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * applications. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <h3>Localized Collation - ORDER BY</h3> 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * two more, <code>LOCALIZED</code>, which changes with the system's current locale 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is the Unicode Collation Algorithm and not tailored to the current locale. 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SQLiteDatabase extends SQLiteClosable { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "Database"; 69082c2af6859dff103e781b372dfde927cc0f869fJeff Hamilton private static final int EVENT_DB_OPERATION = 52000; 70082c2af6859dff103e781b372dfde927cc0f869fJeff Hamilton private static final int EVENT_DB_CORRUPT = 75004; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Algorithms used in ON CONFLICT clause 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.sqlite.org/lang_conflict.html 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 768d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 778d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, an immediate ROLLBACK occurs, 788d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * thus ending the current transaction, and the command aborts with a 798d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * return code of SQLITE_CONSTRAINT. If no transaction is active 808d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * (other than the implied transaction that is created on every command) 818d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * then this algorithm works the same as ABORT. 828d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 838d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_ROLLBACK = 1; 84600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 858d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 868d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs,no ROLLBACK is executed 878d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * so changes from prior commands within the same transaction 888d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are preserved. This is the default behavior. 898d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 908d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_ABORT = 2; 91600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 928d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 938d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, the command aborts with a return 948d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * code SQLITE_CONSTRAINT. But any changes to the database that 958d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * the command made prior to encountering the constraint violation 968d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are preserved and are not backed out. 978d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 988d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_FAIL = 3; 99600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1008d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 1018d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a constraint violation occurs, the one row that contains 1028d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * the constraint violation is not inserted or changed. 1038d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * But the command continues executing normally. Other rows before and 1048d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * after the row that contained the constraint violation continue to be 1058d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * inserted or updated normally. No error is returned. 1068d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1078d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_IGNORE = 4; 108600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1098d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 1108d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * When a UNIQUE constraint violation occurs, the pre-existing rows that 1118d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * are causing the constraint violation are removed prior to inserting 1128d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * or updating the current row. Thus the insert or update always occurs. 1138d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * The command continues executing normally. No error is returned. 1148d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * If a NOT NULL constraint violation occurs, the NULL value is replaced 1158d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * by the default value for that column. If the column has no default 1168d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * value, then the ABORT algorithm is used. If a CHECK constraint 1178d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * violation occurs then the IGNORE algorithm is used. When this conflict 1188d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * resolution strategy deletes rows in order to satisfy a constraint, 1198d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * it does not invoke delete triggers on those rows. 1208d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * This behavior might change in a future release. 1218d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1228d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_REPLACE = 5; 1236eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori 1248d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori /** 1258d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * use the following when no conflict action is specified. 1268d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori */ 1278d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori public static final int CONFLICT_NONE = 0; 1288d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori private static final String[] CONFLICT_VALUES = new String[] 1298d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "}; 130600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Maximum Length Of A LIKE Or GLOB Pattern 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern matching algorithm used in the default LIKE and GLOB implementation 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of SQLite can exhibit O(N^2) performance (where N is the number of characters in 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the pattern) for certain pathological cases. To avoid denial-of-service attacks 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes. 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The default value of this limit is 50000. A modern workstation can evaluate 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly. 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The denial of service problem only comes into play when the pattern length gets 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are at most a few dozen bytes in length, paranoid application developers may 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * want to reduce this parameter to something in the range of a few hundred 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if they know that external users are able to generate arbitrary patterns. 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database for reading and writing. 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If the disk is full, this may fail even before you actually write anything. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@more} Note that the value of this flag is 0, so it is the default. 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int OPEN_READWRITE = 0x00000000; // update native code if changing 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database for reading only. 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the only reliable way to open a database if the disk may be full. 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int OPEN_READONLY = 0x00000001; // update native code if changing 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to open the database without support for localized collators. 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@more} This causes the collator <code>LOCALIZED</code> not to be created. 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You must be consistent when using this flag to use the setting the database was 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * created with. If this is set, {@link #setLocale} will do nothing. 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flag for {@link #openDatabase} to create the database file if it does not already exist. 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Indicates whether the most-recently started transaction has been marked as successful. 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInnerTransactionIsSuccessful; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Valid during the life of a transaction, and indicates whether the entire transaction (the 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * outer one and all of the inner ones) so far has been successful. 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mTransactionIsSuccessful; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 188c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana /** 189c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * Valid during the life of a transaction. 190c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana */ 191c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana private SQLiteTransactionListener mTransactionListener; 192c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Synchronize on this when accessing the database */ 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final ReentrantLock mLock = new ReentrantLock(true); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredWallTime = 0L; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredThreadTime = 0L; 198600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // limit the frequency of complaints about each database to one within 20 sec 200600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // unless run command adb shell setprop log.tag.Database VERBOSE 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_WARNING_WINDOW_IN_MS = 20000; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the lock is held this long then a warning will be printed when it is released. */ 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100; 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 207b43b58d3494426eda6117101635de25bb43efc20Dmitri Plotnikov private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000; 208600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 209d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // The pattern we remove from database filenames before 210d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // potentially logging them. 211d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private static final Pattern EMAIL_IN_DB_PATTERN = Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+"); 212d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastLockMessageTime = 0L; 214600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 215b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Things related to query logging/sampling for debugging 216b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // slow/frequent queries during development. Always log queries 217722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // which take (by default) 500ms+; shorter queries are sampled 218722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // accordingly. Commit statements, which are typically slow, are 219722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // logged together with the most recently executed SQL statement, 220722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // for disambiguation. The 500ms value is configurable via a 221722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // SystemProperty, but developers actively debugging database I/O 222722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // should probably use the regular log tunable, 223722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // LOG_SLOW_QUERIES_PROPERTY, defined below. 224722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick private static int sQueryLogTimeInMillis = 0; // lazily initialized 22512311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private static final int QUERY_LOG_SQL_LENGTH = 64; 226b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private static final String COMMIT_SQL = "COMMIT;"; 22712311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private final Random mRandom = new Random(); 228b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private String mLastSqlStatement = null; 22912311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 230722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // String prefix for slow database query EventLog records that show 231722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // lock acquistions of the database. 232722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:"; 233722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 2346f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** Used by native code, do not rename. make it volatile, so it is thread-safe. */ 2356f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* package */ volatile int mNativeHandle = 0; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used to make temp table names unique */ 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ int mTempTableSequence = 0; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 240a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori /** 241a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori * The size, in bytes, of a block on "/data". This corresponds to the Unix 242a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori * statfs.f_bsize field. note that this field is lazily initialized. 243a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori */ 244a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori private static int sBlockSize = 0; 245a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The path for the database file */ 247ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final String mPath; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 249d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** The anonymized path for the database file for logging purposes */ 250d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String mPathForLogs = null; // lazily populated 251d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The flags passed to open/create */ 253ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final int mFlags; 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The optional factory to use when creating new Cursors */ 256ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final CursorFactory mFactory; 257600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private WeakHashMap<SQLiteClosable, Object> mPrograms; 259600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2605a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 26120f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * for each instance of this class, a LRU cache is maintained to store 2625a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * the compiled query statement ids returned by sqlite database. 263ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * key = SQL statement with "?" for bind args 2645a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * value = {@link SQLiteCompiledSql} 2655a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * If an application opens the database and keeps it open during its entire life, then 266ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * there will not be an overhead of compilation of SQL statements by sqlite. 2675a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * 2685a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * why is this cache NOT static? because sqlite attaches compiledsql statements to the 2695a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is 2705a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * invoked. 2715a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * 2725a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method 2739504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori * (@link setMaxSqlCacheSize(int)}). 2745a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 27520f549fd2f40db524242c9038d7d63356adf95fcVasu Nori // default statement-cache size per database connection ( = instance of this class) 27620f549fd2f40db524242c9038d7d63356adf95fcVasu Nori private int mMaxSqlCacheSize = 25; 27720f549fd2f40db524242c9038d7d63356adf95fcVasu Nori /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries = 27820f549fd2f40db524242c9038d7d63356adf95fcVasu Nori new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) { 27920f549fd2f40db524242c9038d7d63356adf95fcVasu Nori @Override 28020f549fd2f40db524242c9038d7d63356adf95fcVasu Nori public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) { 2819504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori // eldest = least-recently used entry 2829504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori // if it needs to be removed to accommodate a new entry, 2839504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori // close {@link SQLiteCompiledSql} represented by this entry, if not in use 2849504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori // and then let it be removed from the Map. 2859463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // when this is called, the caller must be trying to add a just-compiled stmt 2869463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // to cache; i.e., caller should already have acquired database lock AND 2879463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // the lock on mCompiledQueries. do as assert of these two 2 facts. 2889463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori verifyLockOwner(); 2899463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori if (this.size() <= mMaxSqlCacheSize) { 2909463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // cache is not full. nothing needs to be removed 2919463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori return false; 2929504c70f8862f5ffc55b07bc374e0b18b78a2dc6Vasu Nori } 2939463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // cache is full. eldest will be removed. 2949463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori SQLiteCompiledSql entry = eldest.getValue(); 2959463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori if (!entry.isInUse()) { 2969463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // this {@link SQLiteCompiledSql} is not in use. release it. 2979463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori entry.releaseSqlStatement(); 2989463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 2999463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori // return true, so that this entry is removed automatically by the caller. 3009463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori return true; 30120f549fd2f40db524242c9038d7d63356adf95fcVasu Nori } 30220f549fd2f40db524242c9038d7d63356adf95fcVasu Nori }; 303e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 30420f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)} 30590a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * size of each prepared-statement is between 1K - 6K, depending on the complexity of the 306ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * SQL statement & schema. 307e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 30890a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori public static final int MAX_SQL_CACHE_SIZE = 100; 309e9d9210205b280b4ea0402f78d7dd717068af650Vasu Nori private int mCacheFullWarnings; 31049d02acec84cc0382286fa233135bb5c74d5bdbfVasu Nori private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 1; 3115a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 3125a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** maintain stats about number of cache hits and misses */ 3135a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private int mNumCacheHits; 3145a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori private int mNumCacheMisses; 3155a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 316d606b4bf2c1a2308b40785860853cfb95a77bf58Vasu Nori /** Used to find out where this object was created in case it never got closed. */ 317d606b4bf2c1a2308b40785860853cfb95a77bf58Vasu Nori private Throwable mStackTrace = null; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov // System property that enables logging of slow queries. Specify the threshold in ms. 32090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold"; 32190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private final int mSlowQueryThreshold; 32290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 3236f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** stores the list of statement ids that need to be finalized by sqlite */ 3246f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori private ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>(); 3256f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 326062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors 327062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * Corruption 328062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * */ 329ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private DatabaseErrorHandler mErrorHandler; 330062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param closable 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void addSQLiteClosable(SQLiteClosable closable) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms.put(closable, null); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 342600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void removeSQLiteClosable(SQLiteClosable closable) { 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms.remove(closable); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 350600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 351600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onAllReferencesReleased() { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpen()) { 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbclose(); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attempts to release memory that SQLite holds but does not require to 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * operate properly. Typically this memory will come from the page cache. 362600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of bytes actually released 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 365600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov static public native int releaseMemory(); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Control whether or not the SQLiteDatabase is made thread-safe by using locks 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections. This is pretty expensive, so if you know that your 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * DB will only be used by a single thread then you should set this to false. 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The default is true. 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param lockingEnabled set to true to enable locks, false otherwise 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setLockingEnabled(boolean lockingEnabled) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockingEnabled = lockingEnabled; 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If set then the SQLiteDatabase is made thread-safe by using locks 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mLockingEnabled = true; 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void onCorruption() { 385f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori EventLog.writeEvent(EVENT_DB_CORRUPT, mPath); 386ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori mErrorHandler.onCorruption(this); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. This is a no-op if mLockingEnabled is false. 394600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void lock() { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void lockForced() { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. This is a no-op if mLockingEnabled is false. 430600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void unlock() { 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void unlockForced() { 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkLockHoldTime() { 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long elapsedTime = SystemClock.elapsedRealtime(); 460600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long lockedTime = elapsedTime - mLockAcquiredWallTime; 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT && 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !Log.isLoggable(TAG, Log.VERBOSE) && 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) { 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int threadTime = (int) 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS || 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) { 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastLockMessageTime = elapsedTime; 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was " 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + threadTime + "ms"; 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) { 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg, new Exception()); 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 484ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Begins a transaction in EXCLUSIVE mode. 485ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 486ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Transactions can be nested. 487ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * When the outer transaction is ended all of 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the work done in that transaction and all of the nested transactions will be committed or 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rolled back. The changes will be rolled back if any transaction is ended without being 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 491ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Here is the standard idiom for transactions: 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.beginTransaction(); 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * try { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ... 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.setTransactionSuccessful(); 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } finally { 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.endTransaction(); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre> 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void beginTransaction() { 505c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana beginTransactionWithListener(null /* transactionStatusCallback */); 506c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 507c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana 508c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana /** 509ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Begins a transaction in EXCLUSIVE mode. 510ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 511ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Transactions can be nested. 512ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * When the outer transaction is ended all of 513c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * the work done in that transaction and all of the nested transactions will be committed or 514c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * rolled back. The changes will be rolled back if any transaction is ended without being 515c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 516ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 517c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <p>Here is the standard idiom for transactions: 518c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * 519c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <pre> 520c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.beginTransactionWithListener(listener); 521c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * try { 522c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * ... 523c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.setTransactionSuccessful(); 524c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } finally { 525c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.endTransaction(); 526c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } 527c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * </pre> 528ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * 529c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * @param transactionListener listener that should be notified when the transaction begins, 530c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * commits, or is rolled back, either explicitly or by a call to 531c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * {@link #yieldIfContendedSafely}. 532c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana */ 533c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) { 534ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 535c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori lockForced(); 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean ok = false; 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this thread already had the lock then get out 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() > 1) { 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "Cannot call beginTransaction between " 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "calling setTransactionSuccessful and endTransaction"; 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IllegalStateException e = new IllegalStateException(msg); 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "beginTransaction() failed", e); 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This thread didn't already have the lock, so begin a database 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // transaction now. 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("BEGIN EXCLUSIVE;"); 554c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = transactionListener; 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = true; 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 557c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (transactionListener != null) { 558c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 559c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana transactionListener.onBegin(); 560c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 561c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana execSQL("ROLLBACK;"); 562c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw e; 563c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 564c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!ok) { 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // beginTransaction is called before the try block so we must release the lock in 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the case of failure. 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * End a transaction. See beginTransaction for notes about how to use this and when transactions 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are committed and rolled back. 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void endTransaction() { 580ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyLockOwner(); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = false; 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() != 1) { 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 590c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana RuntimeException savedException = null; 591c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionListener != null) { 592c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 593c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionIsSuccessful) { 594c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onCommit(); 595c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } else { 596c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onRollback(); 597c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 598c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 599c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana savedException = e; 600c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionIsSuccessful = false; 601c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 602c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTransactionIsSuccessful) { 604b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick execSQL(COMMIT_SQL); 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("ROLLBACK;"); 608c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (savedException != null) { 609c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw savedException; 610c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD) { 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "exception during rollback, maybe the DB previously " 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "performed an auto-rollback"); 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 619c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = null; 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGV) { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "unlocked " + Thread.currentThread() 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ", holdCount is " + mLock.getHoldCount()); 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Marks the current transaction as successful. Do not do any more database work between 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * calling this and calling endTransaction. Do as little non-database work as possible in that 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * situation too. If any errors are encountered between this and endTransaction the transaction 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will still be committed. 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IllegalStateException if the current thread is not in a transaction or the 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * transaction is already marked as successful. 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTransactionSuccessful() { 638ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLock.isHeldByCurrentThread()) { 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("no transaction pending"); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "setTransactionSuccessful may only be called once per call to beginTransaction"); 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = true; 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return true if there is a transaction pending 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean inTransaction() { 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLock.getHoldCount() > 0; 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database lock is held by this thread. 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if this thread is holding the database lock. 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByCurrentThread() { 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLock.isHeldByCurrentThread(); 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database is locked by another thread. This is 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * just an estimate, since this status can change at any time, 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * including after the call is made but before the result has 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * been acted upon. 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if the database is locked by another thread 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByOtherThreads() { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !mLock.isHeldByCurrentThread() && mLock.isLocked(); 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will not be yielded. Use yieldIfContendedSafely instead. 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6854a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn @Deprecated 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContended() { 6875c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(false /* do not check yielding */, 6885c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana -1 /* sleepAfterYieldDelay */); 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. This assumes 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that there are no nested transactions (beginTransaction has only been called once) and will 6965c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContendedSafely() { 7005c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/); 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7035c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana /** 7045c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * Temporarily end the transaction to let other threads run. The transaction is assumed to be 7055c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * successful so far. Do not call setTransactionSuccessful before calling this. When this 7065c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * returns a new transaction will have been created but not marked as successful. This assumes 7075c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * that there are no nested transactions (beginTransaction has only been called once) and will 7085c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 7095c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if 7105c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * the lock was actually yielded. This will allow other background threads to make some 7115c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * more progress than they would if we started the transaction immediately. 7125c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @return true if the transaction was yielded 7135c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana */ 7145c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) { 7155c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay); 7165c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 7175c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana 7185c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getQueueLength() == 0) { 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset the lock acquire time since we know that the thread was willing to yield 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the lock at this time. 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setTransactionSuccessful(); 727c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana SQLiteTransactionListener transactionListener = mTransactionListener; 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project endTransaction(); 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (checkFullyYielded) { 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (this.isDbLockedByCurrentThread()) { 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Db locked more than once. yielfIfContended cannot yield"); 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7355c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana if (sleepAfterYieldDelay > 0) { 736600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to 737600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // check if anyone is using the database. If the database is not contended, 738600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // retake the lock and return. 739600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long remainingDelay = sleepAfterYieldDelay; 740600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov while (remainingDelay > 0) { 741600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov try { 742600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ? 743600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay : SLEEP_AFTER_YIELD_QUANTUM); 744600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } catch (InterruptedException e) { 745600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.interrupted(); 746600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 747600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM; 748600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov if (mLock.getQueueLength() == 0) { 749600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov break; 750600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 7515c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 7525c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 753c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana beginTransactionWithListener(transactionListener); 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Maps table names to info about what to which _sync_time column to set 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to NULL on an update. This is used to support syncing. */ 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Map<String, SyncUpdateInfo> mSyncUpdateInfo = 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new HashMap<String, SyncUpdateInfo>(); 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Map<String, String> getSyncedTables() { 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(mSyncUpdateInfo) { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HashMap<String, String> tables = new HashMap<String, String>(); 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String table : mSyncUpdateInfo.keySet()) { 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info = mSyncUpdateInfo.get(table); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (info.deletedTable != null) { 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tables.put(table, info.deletedTable); 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables; 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Internal class used to keep track what needs to be marked as changed 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when an update occurs. This is used for syncing, so the sync engine 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * knows what data has been updated locally. 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private class SyncUpdateInfo { 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates the SyncUpdateInfo class. 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param masterTable The table to set _sync_time to NULL in 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * master table 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey The key that refers to the primary key in table 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo(String masterTable, String deletedTable, 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String foreignKey) { 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.masterTable = masterTable; 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.deletedTable = deletedTable; 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.foreignKey = foreignKey; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The table containing the _sync_time column */ 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String masterTable; 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The deleted table that corresponds to the master table */ 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String deletedTable; 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The key in the local table the row in table. It may be _id, if table 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is the local table. */ 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String foreignKey; 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Used to allow returning sub-classes of {@link Cursor} when calling query. 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface CursorFactory { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver, 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * String, SQLiteQuery)}. 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor newCursor(SQLiteDatabase db, 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursorDriver masterQuery, String editTable, 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteQuery query); 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Open the database according to the flags {@link #OPEN_READWRITE} 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path to database file to open and/or create 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called, or null for default 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags to control database access mode 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the newly opened database 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLiteException if the database cannot be opened 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { 836062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler()); 837062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 838062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 839062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 84074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * Open the database according to the flags {@link #OPEN_READWRITE} 84174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. 84274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 84374f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * <p>Sets the locale of the database to the the system's current locale. 84474f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * Call {@link #setLocale} if you would like something else.</p> 84574f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 84674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be 84774f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * used to handle corruption when sqlite reports database corruption.</p> 84874f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 84974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param path to database file to open and/or create 85074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param factory an optional factory class that is called to instantiate a 85174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * cursor when query is called, or null for default 85274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param flags to control database access mode 85374f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption 85474f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * when sqlite reports database corruption 85574f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @return the newly opened database 85674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @throws SQLiteException if the database cannot be opened 857062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 858062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, 859062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori DatabaseErrorHandler errorHandler) { 860062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags); 861062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 862062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // set the ErrorHandler to be used when SQLite reports exceptions 863ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori sqliteDatabase.mErrorHandler = errorHandler; 864062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Open the database. 867062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori sqliteDatabase.openDatabase(path, flags); 8683ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 8693ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori sqliteDatabase.enableSqlTracing(path); 8703ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori } 8713ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori if (SQLiteDebug.DEBUG_SQL_TIME) { 8723ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori sqliteDatabase.enableSqlProfiling(path); 8733ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori } 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 875062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // Database is not even openable. 876062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori errorHandler.onCorruption(sqliteDatabase); 877c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori sqliteDatabase = new SQLiteDatabase(path, factory, flags); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 879a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori 880a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // set sqlite pagesize to mBlockSize 881a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori if (sBlockSize == 0) { 882a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // TODO: "/data" should be a static final String constant somewhere. it is hardcoded 883a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // in several places right now. 884a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori sBlockSize = new StatFs("/data").getBlockSize(); 885a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori } 886a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori sqliteDatabase.setPageSize(sBlockSize); 887a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori 888ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // add this database to the list of databases opened in this process 889ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori ActiveDatabases.addActiveDatabase(sqliteDatabase); 890c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return sqliteDatabase; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 893062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori private void openDatabase(String path, int flags) { 894062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // Open the database. 895062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori dbopen(path, flags); 896062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 897062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori setLocale(Locale.getDefault()); 898062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } catch (RuntimeException e) { 899062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Log.e(TAG, "Failed to setLocale(). closing the database", e); 900062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori dbclose(); 901062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori throw e; 902062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 903062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 904062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY). 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) { 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openOrCreateDatabase(file.getPath(), factory); 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY). 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) { 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openDatabase(path, factory, CREATE_IF_NECESSARY); 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 920062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * same as {@link #openOrCreateDatabase(String, CursorFactory)} except for an additional param 921062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * errorHandler. 922062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * @param errorHandler the {@link DatabaseErrorHandler} obj to be used when database 923062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * corruption is detected on the database. 924062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 925062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory, 926062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori DatabaseErrorHandler errorHandler) { 927062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler); 928062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 929062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 930062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a memory backed SQLite database. Its contents will be destroyed 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the database is closed. 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a SQLiteDatabase object, or null if the database can't be created 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase create(CursorFactory factory) { 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is a magic string with special meaning for SQLite. 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openDatabase(":memory:", factory, CREATE_IF_NECESSARY); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Close the database. 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void close() { 950f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori if (!isOpen()) { 951f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori return; // already closed 952f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori } 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeClosable(); 956fea6f6dcb70e3fa7f60cab970ed444b5e5e2a3faVasu Nori // finalize ALL statements queued up so far 957fea6f6dcb70e3fa7f60cab970ed444b5e5e2a3faVasu Nori closePendingStatements(); 958f6373e9513002f55bbe00180a5eb9f1051d53547Vasu Nori // close this database instance - regardless of its reference count value 959f6373e9513002f55bbe00180a5eb9f1051d53547Vasu Nori onAllReferencesReleased(); 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void closeClosable() { 966ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* deallocate all compiled SQL statement objects from mCompiledQueries cache. 967e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * this should be done before de-referencing all {@link SQLiteClosable} objects 968e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * from this database object because calling 969e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database 970e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * to be closed. sqlite doesn't let a database close if there are 971e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries. 972e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 973e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori deallocCachedSqlStatements(); 974e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator(); 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iter.hasNext()) { 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<SQLiteClosable, Object> entry = iter.next(); 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteClosable program = entry.getKey(); 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (program != null) { 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project program.onAllReferencesReleasedFromContainer(); 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 982600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 984600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to close the database. 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbclose(); 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the database version. 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database version 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getVersion() { 996ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue(); 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database version. 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param version the new database version 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVersion(int version) { 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA user_version = " + version); 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the maximum size the database may grow to. 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getMaximumSize() { 1014ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null); 1015ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return pageCount * getPageSize(); 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the maximum size the database will grow to. The maximum size cannot 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be set below the current size. 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the maximum database size, in bytes 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long setMaximumSize(long numBytes) { 1026ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long pageSize = getPageSize(); 1027ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long numPages = numBytes / pageSize; 1028ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // If numBytes isn't a multiple of pageSize, bump up a page 1029ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if ((numBytes % pageSize) != 0) { 1030ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori numPages++; 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1032ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages, 1033ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori null); 1034ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return newPageCount * pageSize; 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the current database page size, in bytes. 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database page size, in bytes 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getPageSize() { 1043ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null); 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database page size. The page size must be a power of two. This 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method does not work if any data has been written to the database file, 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and must be called right after the database has been created. 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the database page size, in bytes 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPageSize(long numBytes) { 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA page_size = " + numBytes); 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable. When an update occurs in this table the 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * _sync_dirty field will be set to ensure proper syncing operation. 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to mark as syncable 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * syncable table 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void markTableSyncable(String table, String deletedTable) { 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project markTableSyncable(table, "_id", table, deletedTable); 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable, with the _sync_dirty residing in another 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * table. When an update occurs in this table the _sync_dirty field of the 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row in updateTable with the _id in foreignKey will be set to 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ensure proper syncing operation. 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table an update on this table will trigger a sync time removal 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey this is the column in table whose value is an _id in 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param updateTable this is the table that will have its _sync_dirty 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void markTableSyncable(String table, String foreignKey, 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String updateTable) { 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project markTableSyncable(table, foreignKey, updateTable, null); 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable, with the _sync_dirty residing in another 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * table. When an update occurs in this table the _sync_dirty field of the 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row in updateTable with the _id in foreignKey will be set to 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ensure proper syncing operation. 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table an update on this table will trigger a sync time removal 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey this is the column in table whose value is an _id in 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param updateTable this is the table that will have its _sync_dirty 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void markTableSyncable(String table, String foreignKey, 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String updateTable, String deletedTable) { 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL("SELECT _sync_dirty FROM " + updateTable 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " LIMIT 0"); 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL("SELECT " + foreignKey + " FROM " + table 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " LIMIT 0"); 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable, 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project foreignKey); 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSyncUpdateInfo) { 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSyncUpdateInfo.put(table, info); 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call for each row that is updated in a cursor. 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table the row is in 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param rowId the row ID of the updated row 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void rowUpdated(String table, long rowId) { 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SyncUpdateInfo info; 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSyncUpdateInfo) { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project info = mSyncUpdateInfo.get(table); 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (info != null) { 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("UPDATE " + info.masterTable 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey 1131ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori + " FROM " + table + " WHERE _id=?)", new String[] {String.valueOf(rowId)}); 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Finds the name of the first table, which is editable. 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tables a list of tables 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the first table listed 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String findEditTable(String tables) { 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(tables)) { 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // find the first word terminated by either a space or a comma 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spacepos = tables.indexOf(' '); 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int commapos = tables.indexOf(','); 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spacepos > 0 && (spacepos < commapos || commapos < 0)) { 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, spacepos); 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) { 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, commapos); 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("Invalid tables"); 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compiles an SQL statement into a reusable pre-compiled statement object. 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement and fill in those values with {@link SQLiteProgram#bindString} 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and {@link SQLiteProgram#bindLong} each time you want to run the 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement. Statements may not return result sets larger than 1x1. 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql The raw SQL statement, may contain ? for unknown values to be 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bound later. 1167f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A pre-compiled {@link SQLiteStatement} object. Note that 1168f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link SQLiteStatement}s are not synchronized, see the documentation for more details. 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SQLiteStatement compileStatement(String sql) throws SQLException { 1171ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 1172c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori lock(); 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SQLiteStatement(this, sql); 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 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 * @param limit Limits the number of rows returned by the query, 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1207f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1208f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(boolean distinct, String table, String[] columns, 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return queryWithFactory(null, distinct, table, columns, selection, selectionArgs, 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupBy, having, orderBy, limit); 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1246f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1247f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor queryWithFactory(CursorFactory cursorFactory, 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean distinct, String table, String[] columns, 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 1254ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String sql = SQLiteQueryBuilder.buildQueryString( 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project distinct, table, columns, selection, groupBy, having, orderBy, limit); 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory( 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory, sql, selectionArgs, findEditTable(table)); 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 1286f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1287f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, null /* limit */); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1324f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1325f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy, String limit) { 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, limit); 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a {@link Cursor} over the result set. 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 1343f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1344f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQuery(String sql, String[] selectionArgs) { 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory(null, sql, selectionArgs, null); 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param editTable the name of the first table, which is editable 1359f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1360f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQueryWithFactory( 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CursorFactory cursorFactory, String sql, String[] selectionArgs, 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String editTable) { 1365ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long timeStart = 0; 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 136890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timeStart = System.currentTimeMillis(); 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable); 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 137490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Cursor cursor = null; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 137690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov cursor = driver.query( 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory != null ? cursorFactory : mFactory, 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectionArgs); 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 138090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 138190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 1382020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori // Force query execution 1383020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori int count = -1; 1384020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori if (cursor != null) { 1385020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori count = cursor.getCount(); 1386020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori } 1387020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long duration = System.currentTimeMillis() - timeStart; 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 139090142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || duration >= mSlowQueryThreshold) { 139190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Log.v(SQLiteCursor.TAG, 139290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov "query (" + duration + " ms): " + driver.toString() + ", args are " 139390142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov + (selectionArgs != null 139490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov ? TextUtils.join(",", selectionArgs) 1395020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori : "<null>") + ", count is " + count); 139690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov } 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 139990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov return cursor; 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 1404600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * The cursor will read an initial set of rows and the return to the caller. 1405600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * It will continue to read in batches and send data changed notifications 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the later batches are ready. 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialRead set the initial count of items to read from the cursor 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxRead set the count of items to read on each iteration after the first 1413f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1414f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 1415600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 1416f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * This work is incomplete and not fully tested or reviewed, so currently 1417f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * hidden. 1418f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * @hide 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1420600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public Cursor rawQuery(String sql, String[] selectionArgs, 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int initialRead, int maxRead) { 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, sql, selectionArgs, null); 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.setLoadStyle(initialRead, maxRead); 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return c; 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1427600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insert(String table, String nullColumnHack, ContentValues values) { 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14428d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + values, e); 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertOrThrow(String table, String nullColumnHack, ContentValues values) 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws SQLException { 14648d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replace(String table, String nullColumnHack, ContentValues initialValues) { 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1480600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 14818d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + initialValues, e); 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replaceOrThrow(String table, String nullColumnHack, 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues initialValues) throws SQLException { 1502600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 15038d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * General method for inserting a row into the database. 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for the 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 15168d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for insert conflict resolver 15176eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * @return the row ID of the newly inserted row 15186eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR the primary key of the existing row if the input param 'conflictAlgorithm' = 15198d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * {@link #CONFLICT_IGNORE} 15206eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR -1 if any error 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertWithOnConflict(String table, String nullColumnHack, 15236eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori ContentValues initialValues, int conflictAlgorithm) { 1524ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Measurements show most sql lengths <= 152 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sql = new StringBuilder(152); 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("INSERT"); 15298d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" INTO "); 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Measurements show most values lengths < 40 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder values = new StringBuilder(40); 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Set<Map.Entry<String, Object>> entrySet = null; 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (initialValues != null && initialValues.size() > 0) { 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entrySet = initialValues.valueSet(); 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append('('); 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needSeparator = false; 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (entriesIter.hasNext()) { 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needSeparator) { 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(", "); 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append(", "); 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project needSeparator = true; 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(entry.getKey()); 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append('?'); 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(')'); 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("(" + nullColumnHack + ") "); 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.append("NULL"); 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" VALUES("); 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(values); 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(");"); 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql.toString()); 15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bind the values 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entrySet != null) { 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = entrySet.size(); 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue()); 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Run the program and then cleanup 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long insertedRowId = lastInsertRow(); 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (insertedRowId == -1) { 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + initialValues + " using " + sql); 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "Inserting row " + insertedRowId + " from " 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + initialValues + " using " + sql); 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return insertedRowId; 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for deleting rows in the database. 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to delete from 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when deleting. 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will delete all rows. 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected if a whereClause is passed in, 0 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * otherwise. To remove all rows and get a count pass "1" as the 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * whereClause. 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int delete(String table, String whereClause, String[] whereArgs) { 1613ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 1614c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori lock(); 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement("DELETE FROM " + table 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (!TextUtils.isEmpty(whereClause) 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? " WHERE " + whereClause : "")); 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (whereArgs != null) { 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numArgs = whereArgs.length; 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numArgs; i++) { 16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]); 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return lastChangeCount(); 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { 16508d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE); 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1652600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 16618d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for update conflict resolver 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1664600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public int updateWithOnConflict(String table, ContentValues values, 16656eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori String whereClause, String[] whereArgs, int conflictAlgorithm) { 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (values == null || values.size() == 0) { 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty values"); 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sql = new StringBuilder(120); 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("UPDATE "); 16728d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" SET "); 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Set<Map.Entry<String, Object>> entrySet = values.valueSet(); 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (entriesIter.hasNext()) { 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(entry.getKey()); 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("=?"); 16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entriesIter.hasNext()) { 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(", "); 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(whereClause)) { 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" WHERE "); 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(whereClause); 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1693ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql.toString()); 16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bind the values 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = entrySet.size(); 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entriesIter = entrySet.iterator(); 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bindArg = 1; 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<String, Object> entry = entriesIter.next(); 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue()); 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bindArg++; 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (whereArgs != null) { 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size = whereArgs.length; 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.bindString(bindArg, whereArgs[i]); 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bindArg++; 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Run the program and then cleanup 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numChangedRows = lastChangeCount(); 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql); 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return numChangedRows; 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error updating " + values + " using " + sql); 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1739ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Execute a single SQL statement that is NOT a SELECT 1740ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * or any other SQL statement that returns data. 1741ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1742ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Use of this method is discouraged as it doesn't perform well when issuing the same SQL 1743ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * statement repeatedly (see {@link #compileStatement(String)} to prepare statements for 1744ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * repeated use), and it has no means to return any data (such as the number of affected rows). 1745ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)}, 1746ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * {@link #update(String, ContentValues, String, String[])}, et al, when possible. 1747ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1749ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 1750ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * not supported. 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void execSQL(String sql) throws SQLException { 1754ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 1755c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori long timeStart = SystemClock.uptimeMillis(); 1756c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori lock(); 1757722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX); 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17596f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori closePendingStatements(); 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_execSQL(sql); 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1767b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1768b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Log commit statements along with the most recently executed 1769b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // SQL statement for disambiguation. Note that instance 1770b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // equality to COMMIT_SQL is safe here. 1771b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick if (sql == COMMIT_SQL) { 1772722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL); 1773b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } else { 1774722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(sql, timeStart, null); 1775b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1779ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE. 1780ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1781ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For INSERT statements, use any of the following instead. 1782ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1783ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insert(String, String, ContentValues)}</li> 1784ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insertOrThrow(String, String, ContentValues)}</li> 1785ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li> 1786ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1787ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1788ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For UPDATE statements, use any of the following instead. 1789ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1790ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #update(String, ContentValues, String, String[])}</li> 1791ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li> 1792ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1793ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1794ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For DELETE statements, use any of the following instead. 1795ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1796ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #delete(String, String, String[])}</li> 1797ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1798ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1799ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For example, the following are good candidates for using this method: 1800ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1801ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>ALTER TABLE</li> 1802ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>CREATE or DROP table / trigger / view / index / virtual table</li> 1803ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>REINDEX</li> 1804ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>RELEASE</li> 1805ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>SAVEPOINT</li> 1806ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>PRAGMA that returns no data</li> 1807ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1808ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1810ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 1811ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * not supported. 18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bindArgs only byte[], String, Long and Double are supported in bindArgs. 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void execSQL(String sql, Object[] bindArgs) throws SQLException { 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bindArgs == null) { 18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty bindArgs"); 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1819ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 1820d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long timeStart = SystemClock.uptimeMillis(); 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteStatement statement = null; 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement = compileStatement(sql); 18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bindArgs != null) { 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numArgs = bindArgs.length; 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numArgs; i++) { 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]); 18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.execute(); 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (statement != null) { 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project statement.close(); 18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlock(); 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 184112311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor logTimeStat(sql, timeStart); 18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() { 18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpen()) { 1847d606b4bf2c1a2308b40785860853cfb95a77bf58Vasu Nori Log.e(TAG, "close() was never explicitly called on database '" + 1848d606b4bf2c1a2308b40785860853cfb95a77bf58Vasu Nori mPath + "' ", mStackTrace); 18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeClosable(); 18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onAllReferencesReleased(); 18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Private constructor. See {@link #create} and {@link #openDatabase}. 18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory The factory to use when creating cursors, may be NULL. 18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already 18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * exists, mFlags will be updated appropriately. 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SQLiteDatabase(String path, CursorFactory factory, int flags) { 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null) { 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("path should not be null"); 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFlags = flags; 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 186890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1); 186908b448ea39e9fabfc5212ae6f7226eba4385d189Vasu Nori mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace(); 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFactory = factory; 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms = new WeakHashMap<SQLiteClosable,Object>(); 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return whether the DB is opened as read only. 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if DB is opened as read only 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isReadOnly() { 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mFlags & OPEN_READ_MASK) == OPEN_READONLY; 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the DB is currently open (has not been closed) 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isOpen() { 18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mNativeHandle != 0; 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean needUpgrade(int newVersion) { 18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return newVersion > getVersion(); 18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Getter for the path to the database file. 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the path to our database file. 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final String getPath() { 18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPath; 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1902d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick /* package */ void logTimeStat(String sql, long beginMillis) { 1903722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(sql, beginMillis, null); 1904722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 1905722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 1906722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick /* package */ void logTimeStat(String sql, long beginMillis, String prefix) { 1907b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Keep track of the last statement executed here, as this is 1908b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // the common funnel through which all methods of hitting 1909b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // libsqlite eventually flow. 1910b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick mLastSqlStatement = sql; 1911b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1912e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sample fast queries in proportion to the time taken. 1913e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Quantize the % first, so the logged sampling probability 1914e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // exactly equals the actual sampling rate for this query. 1915e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1916e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori int samplePercent; 1917d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long durationMillis = SystemClock.uptimeMillis() - beginMillis; 1918722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (durationMillis == 0 && prefix == GET_LOCK_LOG_PREFIX) { 1919722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // The common case is locks being uncontended. Don't log those, 1920722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // even at 1%, which is our default below. 1921722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick return; 1922722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 1923722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (sQueryLogTimeInMillis == 0) { 1924722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick sQueryLogTimeInMillis = SystemProperties.getInt("db.db_operation.threshold_ms", 500); 1925722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 1926722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (durationMillis >= sQueryLogTimeInMillis) { 1927e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori samplePercent = 100; 1928722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } else {; 1929722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1; 1930e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (mRandom.nextInt(100) >= samplePercent) return; 19315a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 1932e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1933722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // Note: the prefix will be "COMMIT;" or "GETLOCK:" when non-null. We wait to do 1934722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // it here so we avoid allocating in the common case. 1935722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (prefix != null) { 1936722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick sql = prefix + sql; 1937722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 1938722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 1939e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH); 1940e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1941e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // ActivityThread.currentPackageName() only returns non-null if the 1942e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // current thread is an application main thread. This parameter tells 1943e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // us whether an event loop is blocked, and if so, which app it is. 1944e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // 1945e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sadly, there's no fast way to determine app name if this is *not* a 1946e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // main thread, or when we are invoked via Binder (e.g. ContentProvider). 1947e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Hopefully the full path to the database will be informative enough. 1948e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1949e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori String blockingPackage = ActivityThread.currentPackageName(); 1950e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (blockingPackage == null) blockingPackage = ""; 1951e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1952d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick EventLog.writeEvent( 1953d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick EVENT_DB_OPERATION, 1954d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick getPathForLogs(), 1955d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick sql, 1956d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick durationMillis, 1957d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick blockingPackage, 1958d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick samplePercent); 1959d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1960d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 1961d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** 1962d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * Removes email addresses from database filenames before they're 1963d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * logged to the EventLog where otherwise apps could potentially 1964d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * read them. 1965d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick */ 1966d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String getPathForLogs() { 1967d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPathForLogs != null) { 1968d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 1969d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1970d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath == null) { 1971d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return null; 1972d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1973d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath.indexOf('@') == -1) { 1974d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = mPath; 1975d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } else { 1976d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = EMAIL_IN_DB_PATTERN.matcher(mPath).replaceAll("XX@YY"); 1977d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 1978d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 19795a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19805a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 19815a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 1982e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * Sets the locale for this database. Does nothing if this database has 1983e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * the NO_LOCALIZED_COLLATORS flag set or was opened read only. 1984e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @throws SQLException if the locale could not be set. The most common reason 1985e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * for this is that there is no collator available for the locale you requested. 1986e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * In this case the database remains unchanged. 19875a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 1988e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public void setLocale(Locale locale) { 1989e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori lock(); 1990e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori try { 1991e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori native_setLocale(locale.toString(), mFlags); 1992e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } finally { 1993e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori unlock(); 19945a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19955a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 19965a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 1997ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* package */ void verifyDbIsOpen() { 19989463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori if (!isOpen()) { 19999463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori throw new IllegalStateException("database " + getPath() + " already closed"); 20009463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 2001ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2002ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori 2003ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* package */ void verifyLockOwner() { 2004ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 2005ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (mLockingEnabled && !isDbLockedByCurrentThread()) { 20069463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori throw new IllegalStateException("Don't have database lock!"); 20079463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 20089463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 20099463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori 2010e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* 2011e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * ============================================================================ 2012e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 2013e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * The following methods deal with compiled-sql cache 2014e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * ============================================================================ 2015e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 20165a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 2017ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the 20185a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * cache of compiledQueries attached to 'this'. 2019ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 2020ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL, 20215a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current 20225a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori * mapping is NOT replaced with the new mapping). 20235a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 2024e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) { 20255a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori SQLiteCompiledSql compiledSql = null; 20265a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori synchronized(mCompiledQueries) { 20275a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori // don't insert the new mapping if a mapping already exists 20285a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori compiledSql = mCompiledQueries.get(sql); 20295a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (compiledSql != null) { 2030e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori return; 20315a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 203220f549fd2f40db524242c9038d7d63356adf95fcVasu Nori 20335a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (mCompiledQueries.size() == mMaxSqlCacheSize) { 203449d02acec84cc0382286fa233135bb5c74d5bdbfVasu Nori /* 203549d02acec84cc0382286fa233135bb5c74d5bdbfVasu Nori * cache size of {@link #mMaxSqlCacheSize} is not enough for this app. 203620f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * log a warning. 203720f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * chances are it is NOT using ? for bindargs - or cachesize is too small. 20385a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 203949d02acec84cc0382286fa233135bb5c74d5bdbfVasu Nori if (++mCacheFullWarnings == MAX_WARNINGS_ON_CACHESIZE_CONDITION) { 204049d02acec84cc0382286fa233135bb5c74d5bdbfVasu Nori Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " + 204120f549fd2f40db524242c9038d7d63356adf95fcVasu Nori getPath() + ". Consider increasing cachesize."); 20425a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 204320f549fd2f40db524242c9038d7d63356adf95fcVasu Nori } 204420f549fd2f40db524242c9038d7d63356adf95fcVasu Nori /* add the given SQLiteCompiledSql compiledStatement to cache. 204520f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * no need to worry about the cache size - because {@link #mCompiledQueries} 204620f549fd2f40db524242c9038d7d63356adf95fcVasu Nori * self-limits its size to {@link #mMaxSqlCacheSize}. 204720f549fd2f40db524242c9038d7d63356adf95fcVasu Nori */ 204820f549fd2f40db524242c9038d7d63356adf95fcVasu Nori mCompiledQueries.put(sql, compiledStatement); 204920f549fd2f40db524242c9038d7d63356adf95fcVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 205020f549fd2f40db524242c9038d7d63356adf95fcVasu Nori Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" + 205120f549fd2f40db524242c9038d7d63356adf95fcVasu Nori mCompiledQueries.size() + "|" + sql); 20525a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20535a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 2054e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 2055e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 2056e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori private void deallocCachedSqlStatements() { 2057e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori synchronized (mCompiledQueries) { 2058e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) { 2059e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori compiledSql.releaseSqlStatement(); 2060e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 2061e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mCompiledQueries.clear(); 2062e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } 20635a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20645a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 20655a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 2066ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * From the compiledQueries cache, returns the compiled-statement-id for the given SQL. 2067ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Returns null, if not found in the cache. 20685a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 20695a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) { 20705a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori SQLiteCompiledSql compiledStatement = null; 20715a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori boolean cacheHit; 20725a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori synchronized(mCompiledQueries) { 20735a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null; 20745a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20755a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (cacheHit) { 20765a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mNumCacheHits++; 20775a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } else { 20785a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori mNumCacheMisses++; 20795a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20805a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 20815a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori if (SQLiteDebug.DEBUG_SQL_CACHE) { 20825a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori Log.v(TAG, "|cache_stats|" + 20835a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori getPath() + "|" + mCompiledQueries.size() + 20845a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori "|" + mNumCacheHits + "|" + mNumCacheMisses + 208520f549fd2f40db524242c9038d7d63356adf95fcVasu Nori "|" + cacheHit + "|" + sql); 20865a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20875a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori return compiledStatement; 20885a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20895a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2090e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2091ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Sets the maximum size of the prepared-statement cache for this database. 2092e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * (size of the cache = number of compiled-sql-statements stored in the cache). 2093ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2094ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Maximum cache size can ONLY be increased from its current size (default = 10). 2095ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * If this method is called with smaller size than the current maximum value, 2096ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * then IllegalStateException is thrown. 2097ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2098ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * This method is thread-safe. 2099e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 210090a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE}) 210190a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or 210290a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * > the value set with previous setMaxSqlCacheSize() call. 21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2104e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public synchronized void setMaxSqlCacheSize(int cacheSize) { 2105e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) { 2106e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE); 2107e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } else if (cacheSize < mMaxSqlCacheSize) { 2108e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori throw new IllegalStateException("cannot set cacheSize to a value less than the value " + 2109e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori "set with previous setMaxSqlCacheSize() call."); 21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2111e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori mMaxSqlCacheSize = cacheSize; 21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21146f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* package */ void finalizeStatementLater(int id) { 21156f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (!isOpen()) { 21166f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // database already closed. this statement will already have been finalized. 21176f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 21186f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21196f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori synchronized(mClosedStatementIds) { 21206f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (mClosedStatementIds.contains(id)) { 21216f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // this statement id is already queued up for finalization. 21226f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 21236f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21246f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.add(id); 21256f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21266f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21276f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 21286f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** 21296f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * public visibility only for testing. otherwise, package visibility is sufficient 21306f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * @hide 21316f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori */ 21326f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori public void closePendingStatements() { 21336f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (!isOpen()) { 21346f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // since this database is already closed, no need to finalize anything. 21356f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.clear(); 21366f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 21376f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21386f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori verifyLockOwner(); 21396f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* to minimize synchronization on mClosedStatementIds, make a copy of the list */ 21406f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori ArrayList<Integer> list = new ArrayList<Integer>(mClosedStatementIds.size()); 21416f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori synchronized(mClosedStatementIds) { 21426f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori list.addAll(mClosedStatementIds); 21436f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.clear(); 21446f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21456f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // finalize all the statements from the copied list 21466f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori int size = list.size(); 21476f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori for (int i = 0; i < size; i++) { 21486f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori native_finalize(list.get(i)); 21496f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21506f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21516f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 21526f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** 21536f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * for testing only 21546f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * @hide 21556f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori */ 21566f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori public ArrayList<Integer> getQueuedUpStmtList() { 21576f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return mClosedStatementIds; 21586f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 21596f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 2160c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori static class ActiveDatabases { 2161c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori private static final ActiveDatabases activeDatabases = new ActiveDatabases(); 2162c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases = 2163ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori new HashSet<WeakReference<SQLiteDatabase>>(); 2164c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori private ActiveDatabases() {} // disable instantiation of this class 2165ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori static ActiveDatabases getInstance() { 2166ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return activeDatabases; 2167ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2168ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private static void addActiveDatabase(SQLiteDatabase sqliteDatabase) { 2169ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori activeDatabases.mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase)); 2170ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2171c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2172c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 2173f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori /** 2174f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori * this method is used to collect data about ALL open databases in the current process. 2175f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori * bugreport is a user of this data. 2176f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori */ 2177c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori /* package */ static ArrayList<DbStats> getDbStats() { 2178c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>(); 2179c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) { 2180c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori SQLiteDatabase db = w.get(); 2181c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori if (db == null || !db.isOpen()) { 2182c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori continue; 2183c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2184c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 2185ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori try { 2186ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db 2187ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori int lookasideUsed = db.native_getDbLookaside(); 2188ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori 2189ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // get the lastnode of the dbname 2190ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori String path = db.getPath(); 2191ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori int indx = path.lastIndexOf("/"); 2192ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori String lastnode = path.substring((indx != -1) ? ++indx : 0); 2193ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori 2194ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // get list of attached dbs and for each db, get its size and pagesize 2195ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); 2196ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (attachedDbs == null) { 2197ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori continue; 2198c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2199ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori for (int i = 0; i < attachedDbs.size(); i++) { 2200ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori Pair<String, String> p = attachedDbs.get(i); 2201ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first 2202ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori + ".page_count;", null); 2203ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori 2204ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // first entry in the attached db list is always the main database 2205ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // don't worry about prefixing the dbname with "main" 2206ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori String dbName; 2207ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (i == 0) { 2208ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori dbName = lastnode; 2209ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } else { 2210ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // lookaside is only relevant for the main db 2211ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori lookasideUsed = 0; 2212ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori dbName = " (attached) " + p.first; 2213ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // if the attached db has a path, attach the lastnode from the path to above 2214ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (p.second.trim().length() > 0) { 2215ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori int idx = p.second.lastIndexOf("/"); 2216ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); 2217ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2218ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2219ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (pageCount > 0) { 2220ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), 2221ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses, 2222ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori db.mCompiledQueries.size())); 2223ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2224f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori } 2225ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } catch (SQLiteException e) { 2226ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // ignore. we don't care about exceptions when we are taking adb 2227ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // bugreport! 2228c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2229c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2230c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return dbStatsList; 2231c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2232c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 2233c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori /** 2234ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Returns list of full pathnames of all attached databases including the main database 2235ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * by executing 'pragma database_list' on the database. 2236ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * 2237062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * @return ArrayList of pairs of (database name, database file path) or null if the database 2238062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * is not open. 2239c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori */ 2240062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public ArrayList<Pair<String, String>> getAttachedDbs() { 2241062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (!isOpen()) { 2242f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori return null; 2243f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori } 2244c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>(); 2245062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Cursor c = null; 2246062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 2247062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori c = rawQuery("pragma database_list;", null); 2248062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori while (c.moveToNext()) { 2249062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // sqlite returns a row for each database in the returned list of databases. 2250062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // in each row, 2251062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // 1st column is the database name such as main, or the database 2252062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // name specified on the "ATTACH" command 2253062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // 2nd column is the database file path. 2254062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2))); 2255062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2256062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } finally { 2257062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (c != null) { 2258062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori c.close(); 2259062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2260c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2261c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return attachedDbs; 2262c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2263c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2265ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Runs 'pragma integrity_check' on the given database (and all the attached databases) 2266ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * and returns true if the given database (and all its attached databases) pass integrity_check, 2267062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * false otherwise. 2268ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2269ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * If the result is false, then this method logs the errors reported by the integrity_check 2270062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * command execution. 2271ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2272ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Note that 'pragma integrity_check' on a database can take a long time. 2273062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * 2274062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * @return true if the given database (and all its attached databases) pass integrity_check, 2275ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * false otherwise. 2276062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 2277062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public boolean isDatabaseIntegrityOk() { 2278ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 2279062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs(); 2280062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (attachedDbs == null) { 2281062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " + 2282062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori "be retrieved. probably because the database is closed"); 2283062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2284062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori boolean isDatabaseCorrupt = false; 2285062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori for (int i = 0; i < attachedDbs.size(); i++) { 2286062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Pair<String, String> p = attachedDbs.get(i); 2287062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori SQLiteStatement prog = null; 2288062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 2289062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);"); 2290062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori String rslt = prog.simpleQueryForString(); 2291062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (!rslt.equalsIgnoreCase("ok")) { 2292062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // integrity_checker failed on main or attached databases 2293062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori isDatabaseCorrupt = true; 2294062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt); 2295062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2296062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } finally { 2297062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (prog != null) prog.close(); 2298062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2299062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2300062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori return isDatabaseCorrupt; 2301062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2302062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 2303062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to open the database. 23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbopen(String path, int flags); 23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2311ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Native call to setup tracing of all SQL statements 23123ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 23133ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 23143ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 23153ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori private native void enableSqlTracing(String path); 23163ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 23173ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 2318ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Native call to setup profiling of all SQL statements. 23193ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * currently, sqlite's profiling = printing of execution-time 2320ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * (wall-clock time) of each of the SQL statements, as they 23213ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * are executed. 23223ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 23233ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 23243ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 23253ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori private native void enableSqlProfiling(String path); 23263ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 23273ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to execute a raw SQL statement. {@link #lock} must be held 23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when calling this method. 23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql The raw SQL string 23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native void native_execSQL(String sql) throws SQLException; 23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to set the locale. {@link #lock} must be held when calling 23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this method. 23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native void native_setLocale(String loc, int flags); 23429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the row ID of the last row inserted into the database. 23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the last row inserted into the database. 23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native long lastInsertRow(); 23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of changes made in the last statement executed. 23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of changes made in the last statement executed. 23549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ native int lastChangeCount(); 2356c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 2357c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori /** 2358c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here 2359c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html 2360c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED 2361c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori */ 2362c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori private native int native_getDbLookaside(); 23636f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 23646f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** 23656f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * finalizes the given statement id. 23666f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * 23676f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * @param statementId statement to be finzlied by sqlite 23686f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori */ 23696f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori private final native void native_finalize(int statementId); 23709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2371