SQLiteDatabase.java revision 5a049b0fffd98f5b6b61e43a01345c476d27c1f7
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 1901e4cfc47d0a2c7e7ab383d2fb23224ec52c0301Dianne Hackbornimport android.app.AppGlobals; 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 37cfda9f3a4756c71b3aadd1387419cb3b513dd400Brad Fitzpatrickimport dalvik.system.BlockGuard; 38cfda9f3a4756c71b3aadd1387419cb3b513dd400Brad Fitzpatrick 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 40c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport java.lang.ref.WeakReference; 41c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noriimport java.util.ArrayList; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 44b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Noriimport java.util.LinkedHashMap; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 4712311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnorimport java.util.Random; 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 { 68fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori private static final String TAG = "SQLiteDatabase"; 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 193ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /** 194ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * this member is set if {@link #execSQL(String)} is used to begin and end transactions. 195ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori */ 196ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori private boolean mTransactionUsingExecSql; 197ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Synchronize on this when accessing the database */ 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final ReentrantLock mLock = new ReentrantLock(true); 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredWallTime = 0L; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLockAcquiredThreadTime = 0L; 203600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // limit the frequency of complaints about each database to one within 20 sec 205600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // unless run command adb shell setprop log.tag.Database VERBOSE 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_WARNING_WINDOW_IN_MS = 20000; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the lock is held this long then a warning will be printed when it is released. */ 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 212b43b58d3494426eda6117101635de25bb43efc20Dmitri Plotnikov private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000; 213600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 214d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // The pattern we remove from database filenames before 215d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick // potentially logging them. 216d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private static final Pattern EMAIL_IN_DB_PATTERN = Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+"); 217d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastLockMessageTime = 0L; 219600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 220b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Things related to query logging/sampling for debugging 221b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // slow/frequent queries during development. Always log queries 222722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // which take (by default) 500ms+; shorter queries are sampled 223722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // accordingly. Commit statements, which are typically slow, are 224722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // logged together with the most recently executed SQL statement, 225722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // for disambiguation. The 500ms value is configurable via a 226722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // SystemProperty, but developers actively debugging database I/O 227722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // should probably use the regular log tunable, 228722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // LOG_SLOW_QUERIES_PROPERTY, defined below. 229722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick private static int sQueryLogTimeInMillis = 0; // lazily initialized 23012311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private static final int QUERY_LOG_SQL_LENGTH = 64; 231b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private static final String COMMIT_SQL = "COMMIT;"; 23212311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor private final Random mRandom = new Random(); 233b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick private String mLastSqlStatement = null; 23412311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor 235722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // String prefix for slow database query EventLog records that show 236722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // lock acquistions of the database. 237722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:"; 238722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 2396f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** Used by native code, do not rename. make it volatile, so it is thread-safe. */ 2406f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* package */ volatile int mNativeHandle = 0; 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 242a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori /** 243a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori * The size, in bytes, of a block on "/data". This corresponds to the Unix 244a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori * statfs.f_bsize field. note that this field is lazily initialized. 245a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori */ 246a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori private static int sBlockSize = 0; 247a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The path for the database file */ 249ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final String mPath; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 251d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** The anonymized path for the database file for logging purposes */ 252d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String mPathForLogs = null; // lazily populated 253d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The flags passed to open/create */ 255ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final int mFlags; 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The optional factory to use when creating new Cursors */ 258ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori private final CursorFactory mFactory; 259600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2602134369e803e944af84e73dcaf9356609a5481c6Vasu Nori private final WeakHashMap<SQLiteClosable, Object> mPrograms; 261600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 2625a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 263b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * for each instance of this class, a LRU cache is maintained to store 264b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * the compiled query statement ids returned by sqlite database. 265b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * key = SQL statement with "?" for bind args 266b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * value = {@link SQLiteCompiledSql} 267b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * If an application opens the database and keeps it open during its entire life, then 268b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * there will not be an overhead of compilation of SQL statements by sqlite. 269b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * 270b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * why is this cache NOT static? because sqlite attaches compiledsql statements to the 271b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is 272b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * invoked. 273b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * 274b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method 275b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * (@link #setMaxSqlCacheSize(int)}). 276b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori */ 277b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // default statement-cache size per database connection ( = instance of this class) 278b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori private int mMaxSqlCacheSize = 25; 279b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries = 280b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) { 281b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori @Override 282b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) { 283b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // eldest = least-recently used entry 284b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // if it needs to be removed to accommodate a new entry, 285b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // close {@link SQLiteCompiledSql} represented by this entry, if not in use 286b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // and then let it be removed from the Map. 287b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // when this is called, the caller must be trying to add a just-compiled stmt 288b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // to cache; i.e., caller should already have acquired database lock AND 289b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // the lock on mCompiledQueries. do as assert of these two 2 facts. 290b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori verifyLockOwner(); 291b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori if (this.size() <= mMaxSqlCacheSize) { 292b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // cache is not full. nothing needs to be removed 293b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori return false; 294b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 295b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // cache is full. eldest will be removed. 2965e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori eldest.getValue().releaseIfNotInUse(); 297b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // return true, so that this entry is removed automatically by the caller. 298b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori return true; 299b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 300b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori }; 301b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /** 302b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)} 303b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * size of each prepared-statement is between 1K - 6K, depending on the complexity of the 304ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * SQL statement & schema. 305e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 30690a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori public static final int MAX_SQL_CACHE_SIZE = 100; 3075e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private boolean mCacheFullWarning; 308b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 309b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /** maintain stats about number of cache hits and misses */ 310b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori private int mNumCacheHits; 311b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori private int mNumCacheMisses; 3125a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 313d606b4bf2c1a2308b40785860853cfb95a77bf58Vasu Nori /** Used to find out where this object was created in case it never got closed. */ 3142134369e803e944af84e73dcaf9356609a5481c6Vasu Nori private final Throwable mStackTrace; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31690142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov // System property that enables logging of slow queries. Specify the threshold in ms. 31790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold"; 31890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov private final int mSlowQueryThreshold; 31990142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 3206f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** stores the list of statement ids that need to be finalized by sqlite */ 3212134369e803e944af84e73dcaf9356609a5481c6Vasu Nori private final ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>(); 3226f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 323062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors 324062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * Corruption 325062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * */ 3262134369e803e944af84e73dcaf9356609a5481c6Vasu Nori private final DatabaseErrorHandler mErrorHandler; 327062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 3286c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** The Database connection pool {@link DatabaseConnectionPool}. 3296c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Visibility is package-private for testing purposes. otherwise, private visibility is enough. 3306c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 3316c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /* package */ volatile DatabaseConnectionPool mConnectionPool = null; 3326c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 3336c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** Each database connection handle in the pool is assigned a number 1..N, where N is the 3346c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * size of the connection pool. 3356c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * The main connection handle to which the pool is attached is assigned a value of 0. 3366c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 3376c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /* package */ final short mConnectionNum; 3386c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 33965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori /** on pooled database connections, this member points to the parent ( = main) 34065a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori * database connection handle. 34165a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori * package visibility only for testing purposes 34265a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori */ 34365a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori /* package */ SQLiteDatabase mParentConnObj = null; 34465a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori 345a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori private static final String MEMORY_DB_PATH = ":memory:"; 346a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori 3470732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori /** stores reference to all databases opened in the current process. */ 3480732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori private static ArrayList<WeakReference<SQLiteDatabase>> mActiveDatabases = 3490732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori new ArrayList<WeakReference<SQLiteDatabase>>(); 3500732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori 3512827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori synchronized void addSQLiteClosable(SQLiteClosable closable) { 3522827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori // mPrograms is per instance of SQLiteDatabase and it doesn't actually touch the database 3532827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori // itself. so, there is no need to lock(). 3542827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori mPrograms.put(closable, null); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 356600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 3572827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori synchronized void removeSQLiteClosable(SQLiteClosable closable) { 3582827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori mPrograms.remove(closable); 359600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 360600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onAllReferencesReleased() { 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpen()) { 364ad239ab8fabe53e5f82ff80fb8c9260386dd900cVasu Nori // close the database which will close all pending statements to be finalized also 365ad239ab8fabe53e5f82ff80fb8c9260386dd900cVasu Nori close(); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attempts to release memory that SQLite holds but does not require to 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * operate properly. Typically this memory will come from the page cache. 372600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of bytes actually released 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 375600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov static public native int releaseMemory(); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Control whether or not the SQLiteDatabase is made thread-safe by using locks 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections. This is pretty expensive, so if you know that your 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * DB will only be used by a single thread then you should set this to false. 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The default is true. 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param lockingEnabled set to true to enable locks, false otherwise 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setLockingEnabled(boolean lockingEnabled) { 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockingEnabled = lockingEnabled; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If set then the SQLiteDatabase is made thread-safe by using locks 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * around critical sections 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mLockingEnabled = true; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void onCorruption() { 395f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori EventLog.writeEvent(EVENT_DB_CORRUPT, mPath); 396ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori mErrorHandler.onCorruption(this); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. This is a no-op if mLockingEnabled is false. 404600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void lock() { 4087b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori verifyDbIsOpen(); 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Locks the database for exclusive access. The database lock must be held when 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * touch the native sqlite3* object since it is single threaded and uses 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a polling lock contention algorithm. The lock is recursive, and may be acquired 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple times by the same thread. 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void lockForced() { 4297b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori verifyDbIsOpen(); 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.lock(); 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. This is a no-op if mLockingEnabled is false. 442600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlock() 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void unlock() { 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLockingEnabled) return; 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Releases the database lock. 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unlockForced() 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void unlockForced() { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() == 1) { 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkLockHoldTime(); 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLock.unlock(); 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkLockHoldTime() { 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use elapsed real-time since the CPU may sleep when waiting for IO 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long elapsedTime = SystemClock.elapsedRealtime(); 472600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long lockedTime = elapsedTime - mLockAcquiredWallTime; 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT && 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !Log.isLoggable(TAG, Log.VERBOSE) && 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) { 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) { 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int threadTime = (int) 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000); 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS || 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) { 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastLockMessageTime = elapsedTime; 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was " 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + threadTime + "ms"; 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) { 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg, new Exception()); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 496ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Begins a transaction in EXCLUSIVE mode. 497ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 498ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Transactions can be nested. 499ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * When the outer transaction is ended all of 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the work done in that transaction and all of the nested transactions will be committed or 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rolled back. The changes will be rolled back if any transaction is ended without being 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 503ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Here is the standard idiom for transactions: 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.beginTransaction(); 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * try { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ... 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.setTransactionSuccessful(); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } finally { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * db.endTransaction(); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre> 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void beginTransaction() { 5176c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori beginTransaction(null /* transactionStatusCallback */, true); 5186c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 5196c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 5206c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** 5216c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When 5226c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * the outer transaction is ended all of the work done in that transaction 5236c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * and all of the nested transactions will be committed or rolled back. The 5246c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * changes will be rolled back if any transaction is ended without being 5256c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * marked as clean (by calling setTransactionSuccessful). Otherwise they 5266c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * will be committed. 5276c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 5286c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Here is the standard idiom for transactions: 5296c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * 5306c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <pre> 5316c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.beginTransactionNonExclusive(); 5326c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * try { 5336c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * ... 5346c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.setTransactionSuccessful(); 5356c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * } finally { 5366c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.endTransaction(); 5376c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * } 5386c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * </pre> 5396c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 5406c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori public void beginTransactionNonExclusive() { 5416c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori beginTransaction(null /* transactionStatusCallback */, false); 542c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 543c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana 544c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana /** 545ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Begins a transaction in EXCLUSIVE mode. 546ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 547ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Transactions can be nested. 548ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * When the outer transaction is ended all of 549c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * the work done in that transaction and all of the nested transactions will be committed or 550c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * rolled back. The changes will be rolled back if any transaction is ended without being 551c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. 552ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 553c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <p>Here is the standard idiom for transactions: 554c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * 555c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * <pre> 556c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.beginTransactionWithListener(listener); 557c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * try { 558c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * ... 559c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.setTransactionSuccessful(); 560c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } finally { 561c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * db.endTransaction(); 562c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * } 563c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * </pre> 564ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * 565c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * @param transactionListener listener that should be notified when the transaction begins, 566c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * commits, or is rolled back, either explicitly or by a call to 567c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana * {@link #yieldIfContendedSafely}. 568c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana */ 569c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) { 5706c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori beginTransaction(transactionListener, true); 5716c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 5726c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 5736c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** 5746c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When 5756c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * the outer transaction is ended all of the work done in that transaction 5766c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * and all of the nested transactions will be committed or rolled back. The 5776c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * changes will be rolled back if any transaction is ended without being 5786c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * marked as clean (by calling setTransactionSuccessful). Otherwise they 5796c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * will be committed. 5806c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 5816c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Here is the standard idiom for transactions: 5826c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * 5836c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <pre> 5846c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.beginTransactionWithListenerNonExclusive(listener); 5856c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * try { 5866c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * ... 5876c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.setTransactionSuccessful(); 5886c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * } finally { 5896c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.endTransaction(); 5906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * } 5916c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * </pre> 5926c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * 5936c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * @param transactionListener listener that should be notified when the 5946c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * transaction begins, commits, or is rolled back, either 5956c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * explicitly or by a call to {@link #yieldIfContendedSafely}. 5966c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 5976c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori public void beginTransactionWithListenerNonExclusive( 5986c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori SQLiteTransactionListener transactionListener) { 5996c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori beginTransaction(transactionListener, false); 6006c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 6016c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 6026c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private void beginTransaction(SQLiteTransactionListener transactionListener, 6036c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori boolean exclusive) { 604ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 605c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori lockForced(); 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean ok = false; 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this thread already had the lock then get out 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() > 1) { 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "Cannot call beginTransaction between " 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "calling setTransactionSuccessful and endTransaction"; 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IllegalStateException e = new IllegalStateException(msg); 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "beginTransaction() failed", e); 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This thread didn't already have the lock, so begin a database 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // transaction now. 62357feb5d9a7fd5329c2ae5daeca0ce8f10a7372a7Vasu Nori if (exclusive && mConnectionPool == null) { 6246c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori execSQL("BEGIN EXCLUSIVE;"); 6256c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } else { 6266c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori execSQL("BEGIN IMMEDIATE;"); 6276c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 628c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = transactionListener; 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = true; 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 631c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (transactionListener != null) { 632c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 633c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana transactionListener.onBegin(); 634c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 635c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana execSQL("ROLLBACK;"); 636c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw e; 637c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 638c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ok = true; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!ok) { 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // beginTransaction is called before the try block so we must release the lock in 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the case of failure. 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * End a transaction. See beginTransaction for notes about how to use this and when transactions 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are committed and rolled back. 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void endTransaction() { 654ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyLockOwner(); 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = false; 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransactionIsSuccessful = false; 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getHoldCount() != 1) { 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 664c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana RuntimeException savedException = null; 665c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionListener != null) { 666c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana try { 667c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (mTransactionIsSuccessful) { 668c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onCommit(); 669c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } else { 670c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener.onRollback(); 671c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 672c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } catch (RuntimeException e) { 673c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana savedException = e; 674c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionIsSuccessful = false; 675c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 676c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTransactionIsSuccessful) { 678b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick execSQL(COMMIT_SQL); 6796c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // if write-ahead logging is used, we have to take care of checkpoint. 6806c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // TODO: should applications be given the flexibility of choosing when to 6816c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // trigger checkpoint? 6826c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // for now, do checkpoint after every COMMIT because that is the fastest 6836c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // way to guarantee that readers will see latest data. 6846c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // but this is the slowest way to run sqlite with in write-ahead logging mode. 6856c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (this.mConnectionPool != null) { 6866c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori execSQL("PRAGMA wal_checkpoint;"); 6876c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 6886c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori Log.i(TAG, "PRAGMA wal_Checkpoint done"); 6896c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 6906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("ROLLBACK;"); 694c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana if (savedException != null) { 695c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana throw savedException; 696c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana } 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD) { 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "exception during rollback, maybe the DB previously " 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "performed an auto-rollback"); 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 705c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana mTransactionListener = null; 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unlockForced(); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGV) { 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "unlocked " + Thread.currentThread() 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ", holdCount is " + mLock.getHoldCount()); 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Marks the current transaction as successful. Do not do any more database work between 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * calling this and calling endTransaction. Do as little non-database work as possible in that 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * situation too. If any errors are encountered between this and endTransaction the transaction 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will still be committed. 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IllegalStateException if the current thread is not in a transaction or the 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * transaction is already marked as successful. 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTransactionSuccessful() { 724ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mLock.isHeldByCurrentThread()) { 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("no transaction pending"); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerTransactionIsSuccessful) { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "setTransactionSuccessful may only be called once per call to beginTransaction"); 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerTransactionIsSuccessful = true; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return true if there is a transaction pending 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean inTransaction() { 739ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori return mLock.getHoldCount() > 0 || mTransactionUsingExecSql; 740ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 741ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori 742ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /* package */ synchronized void setTransactionUsingExecSqlFlag() { 743ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 744ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, "found execSQL('begin transaction')"); 745ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 746ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori mTransactionUsingExecSql = true; 747ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 748ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori 749ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /* package */ synchronized void resetTransactionUsingExecSqlFlag() { 750ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 751ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (mTransactionUsingExecSql) { 752ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, "found execSQL('commit or end or rollback')"); 753ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 754ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 755ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori mTransactionUsingExecSql = false; 756ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 757ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori 758ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /** 759ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * Returns true if the caller is considered part of the current transaction, if any. 760ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * <p> 761ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * Caller is part of the current transaction if either of the following is true 762ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * <ol> 763ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * <li>If transaction is started by calling beginTransaction() methods AND if the caller is 764ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * in the same thread as the thread that started the transaction. 765ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * </li> 766ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * <li>If the transaction is started by calling {@link #execSQL(String)} like this: 767ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * execSQL("BEGIN transaction"). In this case, every thread in the process is considered 768ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * part of the current transaction.</li> 769ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * </ol> 770ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * 771ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * @return true if the caller is considered part of the current transaction, if any. 772ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori */ 773ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /* package */ synchronized boolean amIInTransaction() { 774ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori // always do this test on the main database connection - NOT on pooled database connection 775ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori // since transactions always occur on the main database connections only. 776ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori SQLiteDatabase db = (isPooledConnection()) ? mParentConnObj : this; 777ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori boolean b = (!db.inTransaction()) ? false : 778ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori db.mTransactionUsingExecSql || db.mLock.isHeldByCurrentThread(); 779ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 780ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, "amIinTransaction: " + b); 781ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 782ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori return b; 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database lock is held by this thread. 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if this thread is holding the database lock. 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByCurrentThread() { 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLock.isHeldByCurrentThread(); 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the database is locked by another thread. This is 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * just an estimate, since this status can change at any time, 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * including after the call is made but before the result has 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * been acted upon. 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true, if the database is locked by another thread 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isDbLockedByOtherThreads() { 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !mLock.isHeldByCurrentThread() && mLock.isLocked(); 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will not be yielded. Use yieldIfContendedSafely instead. 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8144a51c20ce607c74914f90fd897f04080121ac13bDianne Hackborn @Deprecated 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContended() { 8165c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(false /* do not check yielding */, 8175c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana -1 /* sleepAfterYieldDelay */); 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Temporarily end the transaction to let other threads run. The transaction is assumed to be 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * successful so far. Do not call setTransactionSuccessful before calling this. When this 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returns a new transaction will have been created but not marked as successful. This assumes 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that there are no nested transactions (beginTransaction has only been called once) and will 8255c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the transaction was yielded 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean yieldIfContendedSafely() { 8295c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/); 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8325c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana /** 8335c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * Temporarily end the transaction to let other threads run. The transaction is assumed to be 8345c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * successful so far. Do not call setTransactionSuccessful before calling this. When this 8355c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * returns a new transaction will have been created but not marked as successful. This assumes 8365c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * that there are no nested transactions (beginTransaction has only been called once) and will 8375c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * throw an exception if that is not the case. 8385c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if 8395c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * the lock was actually yielded. This will allow other background threads to make some 8405c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * more progress than they would if we started the transaction immediately. 8415c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana * @return true if the transaction was yielded 8425c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana */ 8435c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) { 8445c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay); 8455c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 8465c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana 8475c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) { 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLock.getQueueLength() == 0) { 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset the lock acquire time since we know that the thread was willing to yield 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the lock at this time. 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredWallTime = SystemClock.elapsedRealtime(); 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setTransactionSuccessful(); 856c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana SQLiteTransactionListener transactionListener = mTransactionListener; 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project endTransaction(); 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (checkFullyYielded) { 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (this.isDbLockedByCurrentThread()) { 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException( 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Db locked more than once. yielfIfContended cannot yield"); 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8645c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana if (sleepAfterYieldDelay > 0) { 865600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to 866600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // check if anyone is using the database. If the database is not contended, 867600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov // retake the lock and return. 868600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov long remainingDelay = sleepAfterYieldDelay; 869600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov while (remainingDelay > 0) { 870600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov try { 871600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ? 872600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay : SLEEP_AFTER_YIELD_QUANTUM); 873600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } catch (InterruptedException e) { 874600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov Thread.interrupted(); 875600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 876600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM; 877600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov if (mLock.getQueueLength() == 0) { 878600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov break; 879600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 8805c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 8815c7aede8d69f4f0ad617d39decd4453b029ba6afFred Quintana } 882c4516a7b62de525e3d6d5e76851bdfaf12c11f05Fred Quintana beginTransactionWithListener(transactionListener); 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 88795675137f417173dc711a2d39232a1f545799013Vasu Nori * @deprecated This method no longer serves any useful purpose and has been deprecated. 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 88995675137f417173dc711a2d39232a1f545799013Vasu Nori @Deprecated 89095675137f417173dc711a2d39232a1f545799013Vasu Nori public Map<String, String> getSyncedTables() { 89195675137f417173dc711a2d39232a1f545799013Vasu Nori return new HashMap<String, String>(0); 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Used to allow returning sub-classes of {@link Cursor} when calling query. 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface CursorFactory { 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See 900bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * {@link SQLiteCursor#SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)}. 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor newCursor(SQLiteDatabase db, 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursorDriver masterQuery, String editTable, 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteQuery query); 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Open the database according to the flags {@link #OPEN_READWRITE} 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path to database file to open and/or create 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called, or null for default 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags to control database access mode 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the newly opened database 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLiteException if the database cannot be opened 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { 922062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler()); 923062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 924062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 925062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 92674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * Open the database according to the flags {@link #OPEN_READWRITE} 92774f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. 92874f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 92974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * <p>Sets the locale of the database to the the system's current locale. 93074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * Call {@link #setLocale} if you would like something else.</p> 93174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 93274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be 93374f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * used to handle corruption when sqlite reports database corruption.</p> 93474f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * 93574f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param path to database file to open and/or create 93674f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param factory an optional factory class that is called to instantiate a 93774f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * cursor when query is called, or null for default 93874f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param flags to control database access mode 93974f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption 94074f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * when sqlite reports database corruption 94174f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @return the newly opened database 94274f170f9468d3cf6d7d0ef453320141a3e63571bVasu Nori * @throws SQLiteException if the database cannot be opened 943062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 944062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, 945062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori DatabaseErrorHandler errorHandler) { 9466c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori SQLiteDatabase sqliteDatabase = openDatabase(path, factory, flags, errorHandler, 9476c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori (short) 0 /* the main connection handle */); 948a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori 949a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // set sqlite pagesize to mBlockSize 950a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori if (sBlockSize == 0) { 951a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // TODO: "/data" should be a static final String constant somewhere. it is hardcoded 952a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori // in several places right now. 953a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori sBlockSize = new StatFs("/data").getBlockSize(); 954a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori } 955a8c24904ebb301d1a95f9c780aabbe4ebe7026c8Vasu Nori sqliteDatabase.setPageSize(sBlockSize); 95657feb5d9a7fd5329c2ae5daeca0ce8f10a7372a7Vasu Nori //STOPSHIP - uncomment the following line 95757feb5d9a7fd5329c2ae5daeca0ce8f10a7372a7Vasu Nori //sqliteDatabase.setJournalMode(path, "TRUNCATE"); 95857feb5d9a7fd5329c2ae5daeca0ce8f10a7372a7Vasu Nori // STOPSHIP remove the following lines 9597b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) { 9607b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori sqliteDatabase.enableWriteAheadLogging(); 9617b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori } 9627b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori // END STOPSHIP 963f9e2bd085f50d557ec48f4e4728fe5a79d37ede5Vasu Nori 964ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // add this database to the list of databases opened in this process 9650732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori synchronized(mActiveDatabases) { 9660732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase)); 9670732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori } 968c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return sqliteDatabase; 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9716c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, 9726c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori DatabaseErrorHandler errorHandler, short connectionNum) { 9736c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori SQLiteDatabase db = new SQLiteDatabase(path, factory, flags, errorHandler, connectionNum); 974062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 975ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 976ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, "opening the db : " + path); 977ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 9786c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // Open the database. 9796c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.dbopen(path, flags); 9806c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.setLocale(Locale.getDefault()); 9816c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 9826c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.enableSqlTracing(path, connectionNum); 9836c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 9846c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (SQLiteDebug.DEBUG_SQL_TIME) { 9856c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.enableSqlProfiling(path, connectionNum); 9866c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 9876c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori return db; 9886c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } catch (SQLiteDatabaseCorruptException e) { 9896c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.mErrorHandler.onCorruption(db); 9906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori return SQLiteDatabase.openDatabase(path, factory, flags, errorHandler); 9916c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } catch (SQLiteException e) { 9926c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori Log.e(TAG, "Failed to open the database. closing it.", e); 9936c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori db.close(); 994062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori throw e; 995062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 996062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 997062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY). 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) { 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openOrCreateDatabase(file.getPath(), factory); 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY). 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) { 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return openDatabase(path, factory, CREATE_IF_NECESSARY); 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10136c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler). 1014062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 1015062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory, 1016062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori DatabaseErrorHandler errorHandler) { 1017062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler); 1018062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 1019062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 1020a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori private void setJournalMode(final String dbPath, final String mode) { 1021a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori // journal mode can be set only for non-memory databases 1022a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori if (!dbPath.equalsIgnoreCase(MEMORY_DB_PATH)) { 1023a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori String s = DatabaseUtils.stringForQuery(this, "PRAGMA journal_mode=" + mode, null); 1024a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori if (!s.equalsIgnoreCase(mode)) { 1025a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori Log.e(TAG, "setting journal_mode to " + mode + " failed for db: " + dbPath + 1026a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori " (on pragma set journal_mode, sqlite returned:" + s); 1027a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori } 1028a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori } 1029a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori } 1030a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori 1031062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a memory backed SQLite database. Its contents will be destroyed 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the database is closed. 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Sets the locale of the database to the the system's current locale. 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call {@link #setLocale} if you would like something else.</p> 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory an optional factory class that is called to instantiate a 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cursor when query is called 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a SQLiteDatabase object, or null if the database can't be created 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SQLiteDatabase create(CursorFactory factory) { 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This is a magic string with special meaning for SQLite. 1044a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori return openDatabase(MEMORY_DB_PATH, factory, CREATE_IF_NECESSARY); 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Close the database. 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void close() { 1051f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori if (!isOpen()) { 1052f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori return; // already closed 1053f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori } 1054ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 10557501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori Log.i(TAG, "closing db: " + mPath + " (connection # " + mConnectionNum); 10567501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori } 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lock(); 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeClosable(); 1060fea6f6dcb70e3fa7f60cab970ed444b5e5e2a3faVasu Nori // finalize ALL statements queued up so far 1061fea6f6dcb70e3fa7f60cab970ed444b5e5e2a3faVasu Nori closePendingStatements(); 10629d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood releaseCustomFunctions(); 1063f6373e9513002f55bbe00180a5eb9f1051d53547Vasu Nori // close this database instance - regardless of its reference count value 1064422dad0f5069a96c002faf31540bf471a7052585Vasu Nori closeDatabase(); 10656c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (mConnectionPool != null) { 1066ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 1067ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori assert mConnectionPool != null; 1068ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, mConnectionPool.toString()); 1069ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 10706c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori mConnectionPool.close(); 10716c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1073422dad0f5069a96c002faf31540bf471a7052585Vasu Nori unlock(); 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void closeClosable() { 1078ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* deallocate all compiled SQL statement objects from mCompiledQueries cache. 1079e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * this should be done before de-referencing all {@link SQLiteClosable} objects 1080e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * from this database object because calling 1081e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database 1082e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * to be closed. sqlite doesn't let a database close if there are 1083e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries. 1084e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori */ 1085b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori deallocCachedSqlStatements(); 1086e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator(); 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iter.hasNext()) { 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map.Entry<SQLiteClosable, Object> entry = iter.next(); 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteClosable program = entry.getKey(); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (program != null) { 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project program.onAllReferencesReleasedFromContainer(); 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1094600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov } 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1096600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1098422dad0f5069a96c002faf31540bf471a7052585Vasu Nori * package level access for testing purposes 1099422dad0f5069a96c002faf31540bf471a7052585Vasu Nori */ 1100422dad0f5069a96c002faf31540bf471a7052585Vasu Nori /* package */ void closeDatabase() throws SQLiteException { 1101422dad0f5069a96c002faf31540bf471a7052585Vasu Nori try { 1102422dad0f5069a96c002faf31540bf471a7052585Vasu Nori dbclose(); 1103422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } catch (SQLiteUnfinalizedObjectsException e) { 1104422dad0f5069a96c002faf31540bf471a7052585Vasu Nori String msg = e.getMessage(); 1105422dad0f5069a96c002faf31540bf471a7052585Vasu Nori String[] tokens = msg.split(",", 2); 1106422dad0f5069a96c002faf31540bf471a7052585Vasu Nori int stmtId = Integer.parseInt(tokens[0]); 1107422dad0f5069a96c002faf31540bf471a7052585Vasu Nori // get extra info about this statement, if it is still to be released by closeClosable() 1108422dad0f5069a96c002faf31540bf471a7052585Vasu Nori Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator(); 1109422dad0f5069a96c002faf31540bf471a7052585Vasu Nori boolean found = false; 1110422dad0f5069a96c002faf31540bf471a7052585Vasu Nori while (iter.hasNext()) { 1111422dad0f5069a96c002faf31540bf471a7052585Vasu Nori Map.Entry<SQLiteClosable, Object> entry = iter.next(); 1112422dad0f5069a96c002faf31540bf471a7052585Vasu Nori SQLiteClosable program = entry.getKey(); 1113422dad0f5069a96c002faf31540bf471a7052585Vasu Nori if (program != null && program instanceof SQLiteProgram) { 1114422dad0f5069a96c002faf31540bf471a7052585Vasu Nori SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql; 1115422dad0f5069a96c002faf31540bf471a7052585Vasu Nori if (compiledSql.nStatement == stmtId) { 1116422dad0f5069a96c002faf31540bf471a7052585Vasu Nori msg = compiledSql.toString(); 1117422dad0f5069a96c002faf31540bf471a7052585Vasu Nori found = true; 1118422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1119422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1120422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1121422dad0f5069a96c002faf31540bf471a7052585Vasu Nori if (!found) { 1122422dad0f5069a96c002faf31540bf471a7052585Vasu Nori // the statement is already released by closeClosable(). is it waiting to be 1123422dad0f5069a96c002faf31540bf471a7052585Vasu Nori // finalized? 1124422dad0f5069a96c002faf31540bf471a7052585Vasu Nori if (mClosedStatementIds.contains(stmtId)) { 1125422dad0f5069a96c002faf31540bf471a7052585Vasu Nori Log.w(TAG, "this shouldn't happen. finalizing the statement now: "); 1126422dad0f5069a96c002faf31540bf471a7052585Vasu Nori closePendingStatements(); 1127422dad0f5069a96c002faf31540bf471a7052585Vasu Nori // try to close the database again 1128422dad0f5069a96c002faf31540bf471a7052585Vasu Nori closeDatabase(); 1129422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1130422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } else { 1131422dad0f5069a96c002faf31540bf471a7052585Vasu Nori // the statement is not yet closed. most probably programming error in the app. 1132422dad0f5069a96c002faf31540bf471a7052585Vasu Nori Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg); 1133422dad0f5069a96c002faf31540bf471a7052585Vasu Nori throw e; 1134422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1135422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1136422dad0f5069a96c002faf31540bf471a7052585Vasu Nori } 1137422dad0f5069a96c002faf31540bf471a7052585Vasu Nori 1138422dad0f5069a96c002faf31540bf471a7052585Vasu Nori /** 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to close the database. 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbclose(); 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11449d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * A callback interface for a custom sqlite3 function. 11459d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * This can be used to create a function that can be called from 11469d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * sqlite3 database triggers. 11479d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * @hide 11489d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood */ 11499d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood public interface CustomFunction { 11509d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood public void callback(String[] args); 11519d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11529d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood 11539d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood /** 11549d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * Registers a CustomFunction callback as a function that can be called from 11559d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * sqlite3 database triggers. 11569d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * @param name the name of the sqlite3 function 11579d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * @param numArgs the number of arguments for the function 11589d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * @param function callback to call when the function is executed 11599d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood * @hide 11609d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood */ 11619d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood public void addCustomFunction(String name, int numArgs, CustomFunction function) { 11629d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood verifyDbIsOpen(); 11639d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood synchronized (mCustomFunctions) { 11649d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood int ref = native_addCustomFunction(name, numArgs, function); 11659d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood if (ref != 0) { 11669d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood // save a reference to the function for cleanup later 11679d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood mCustomFunctions.add(new Integer(ref)); 11689d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } else { 11699d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood throw new SQLiteException("failed to add custom function " + name); 11709d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11719d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11729d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11739d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood 11749d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood private void releaseCustomFunctions() { 11759d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood synchronized (mCustomFunctions) { 11769d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood for (int i = 0; i < mCustomFunctions.size(); i++) { 11779d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood Integer function = mCustomFunctions.get(i); 11789d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood native_releaseCustomFunction(function.intValue()); 11799d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11809d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood mCustomFunctions.clear(); 11819d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11829d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 11839d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood 11849d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood // list of CustomFunction references so we can clean up when the database closes 11859d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood private final ArrayList<Integer> mCustomFunctions = 11869d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood new ArrayList<Integer>(); 11879d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood 11889d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood private native int native_addCustomFunction(String name, int numArgs, CustomFunction function); 11899d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood private native void native_releaseCustomFunction(int function); 11909d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood 11919d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood /** 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the database version. 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database version 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getVersion() { 1197ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue(); 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database version. 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param version the new database version 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVersion(int version) { 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA user_version = " + version); 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the maximum size the database may grow to. 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getMaximumSize() { 1215ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null); 1216ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return pageCount * getPageSize(); 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the maximum size the database will grow to. The maximum size cannot 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be set below the current size. 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the maximum database size, in bytes 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the new maximum database size 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long setMaximumSize(long numBytes) { 1227ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long pageSize = getPageSize(); 1228ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long numPages = numBytes / pageSize; 1229ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori // If numBytes isn't a multiple of pageSize, bump up a page 1230ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if ((numBytes % pageSize) != 0) { 1231ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori numPages++; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1233ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages, 1234ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori null); 1235ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return newPageCount * pageSize; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the current database page size, in bytes. 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the database page size, in bytes 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getPageSize() { 1244ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null); 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the database page size. The page size must be a power of two. This 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method does not work if any data has been written to the database file, 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and must be called right after the database has been created. 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param numBytes the database page size, in bytes 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPageSize(long numBytes) { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project execSQL("PRAGMA page_size = " + numBytes); 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable. When an update occurs in this table the 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * _sync_dirty field will be set to ensure proper syncing operation. 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to mark as syncable 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param deletedTable The deleted table that corresponds to the 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * syncable table 126595675137f417173dc711a2d39232a1f545799013Vasu Nori * @deprecated This method no longer serves any useful purpose and has been deprecated. 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 126795675137f417173dc711a2d39232a1f545799013Vasu Nori @Deprecated 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void markTableSyncable(String table, String deletedTable) { 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark this table as syncable, with the _sync_dirty residing in another 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * table. When an update occurs in this table the _sync_dirty field of the 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row in updateTable with the _id in foreignKey will be set to 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ensure proper syncing operation. 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table an update on this table will trigger a sync time removal 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param foreignKey this is the column in table whose value is an _id in 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updateTable 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param updateTable this is the table that will have its _sync_dirty 128195675137f417173dc711a2d39232a1f545799013Vasu Nori * @deprecated This method no longer serves any useful purpose and has been deprecated. 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 128395675137f417173dc711a2d39232a1f545799013Vasu Nori @Deprecated 128495675137f417173dc711a2d39232a1f545799013Vasu Nori public void markTableSyncable(String table, String foreignKey, String updateTable) { 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Finds the name of the first table, which is editable. 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tables a list of tables 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the first table listed 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String findEditTable(String tables) { 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(tables)) { 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // find the first word terminated by either a space or a comma 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spacepos = tables.indexOf(' '); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int commapos = tables.indexOf(','); 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spacepos > 0 && (spacepos < commapos || commapos < 0)) { 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, spacepos); 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) { 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables.substring(0, commapos); 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tables; 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("Invalid tables"); 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compiles an SQL statement into a reusable pre-compiled statement object. 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement and fill in those values with {@link SQLiteProgram#bindString} 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and {@link SQLiteProgram#bindLong} each time you want to run the 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * statement. Statements may not return result sets larger than 1x1. 13162827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori *<p> 13172827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori * No two threads should be using the same {@link SQLiteStatement} at the same time. 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql The raw SQL statement, may contain ? for unknown values to be 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bound later. 1321f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A pre-compiled {@link SQLiteStatement} object. Note that 1322f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link SQLiteStatement}s are not synchronized, see the documentation for more details. 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SQLiteStatement compileStatement(String sql) throws SQLException { 1325ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 13260732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori return new SQLiteStatement(this, sql, null); 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1356f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1357f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(boolean distinct, String table, String[] columns, 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return queryWithFactory(null, distinct, table, columns, selection, selectionArgs, 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupBy, having, orderBy, limit); 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given URL, returning a {@link Cursor} over the result set. 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1395f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1396f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor queryWithFactory(CursorFactory cursorFactory, 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean distinct, String table, String[] columns, 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String having, String orderBy, String limit) { 1403ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String sql = SQLiteQueryBuilder.buildQueryString( 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project distinct, table, columns, selection, groupBy, having, orderBy, limit); 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory( 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory, sql, selectionArgs, findEditTable(table)); 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 1435f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1436f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy) { 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, null /* limit */); 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Query the given table, returning a {@link Cursor} over the result set. 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table The table name to compile the query against. 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param columns A list of which columns to return. Passing null will 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return all columns, which is discouraged to prevent reading 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * data from storage that isn't going to be used. 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selection A filter declaring which rows to return, formatted as an 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SQL WHERE clause (excluding the WHERE itself). Passing null 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will return all rows for the given table. 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in selection, which will be 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * replaced by the values from selectionArgs, in order that they 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * appear in the selection. The values will be bound as Strings. 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will cause the rows to not be grouped. 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all row groups to be included, and is required when row 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * grouping is not being used. 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default sort order, which may be unordered. 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param limit Limits the number of rows returned by the query, 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 1473f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1474f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Cursor 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor query(String table, String[] columns, String selection, 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs, String groupBy, String having, 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String orderBy, String limit) { 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(false, table, columns, selection, selectionArgs, groupBy, 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project having, orderBy, limit); 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a {@link Cursor} over the result set. 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 1492f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1493f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQuery(String sql, String[] selectionArgs) { 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rawQueryWithFactory(null, sql, selectionArgs, null); 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param cursorFactory the cursor factory to use, or null for the default factory 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param editTable the name of the first table, which is editable 1508f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1509f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Cursor rawQueryWithFactory( 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CursorFactory cursorFactory, String sql, String[] selectionArgs, 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String editTable) { 1514ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 1515cfda9f3a4756c71b3aadd1387419cb3b513dd400Brad Fitzpatrick BlockGuard.getThreadPolicy().onReadFromDisk(); 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long timeStart = 0; 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 151890142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timeStart = System.currentTimeMillis(); 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15226c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori SQLiteDatabase db = getDbConnection(sql); 15236c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(db, sql, editTable); 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 152590142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Cursor cursor = null; 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 152790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov cursor = driver.query( 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursorFactory != null ? cursorFactory : mFactory, 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selectionArgs); 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 153190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || mSlowQueryThreshold != -1) { 153290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov 1533020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori // Force query execution 1534020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori int count = -1; 1535020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori if (cursor != null) { 1536020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori count = cursor.getCount(); 1537020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori } 1538020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long duration = System.currentTimeMillis() - timeStart; 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 154190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov if (Config.LOGV || duration >= mSlowQueryThreshold) { 154290142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov Log.v(SQLiteCursor.TAG, 154390142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov "query (" + duration + " ms): " + driver.toString() + ", args are " 154490142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov + (selectionArgs != null 154590142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov ? TextUtils.join(",", selectionArgs) 1546020e5345795a157d7829ebbe4d7864595dafc576Vasu Nori : "<null>") + ", count is " + count); 154790142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov } 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15496c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori releaseDbConnection(db); 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 155190142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov return cursor; 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Runs the provided SQL and returns a cursor over the result set. 1556600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * The cursor will read an initial set of rows and the return to the caller. 1557600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * It will continue to read in batches and send data changed notifications 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the later batches are ready. 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param sql the SQL query. The SQL string must not be ; terminated 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param selectionArgs You may include ?s in where clause in the query, 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be replaced by the values from selectionArgs. The 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * values will be bound as Strings. 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialRead set the initial count of items to read from the cursor 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxRead set the count of items to read on each iteration after the first 1565f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * @return A {@link Cursor} object, which is positioned before the first entry. Note that 1566f3ca9a5c7e87319c934b5815566054d2e5c2085fJeff Hamilton * {@link Cursor}s are not synchronized, see the documentation for more details. 1567600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov * 1568f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * This work is incomplete and not fully tested or reviewed, so currently 1569f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * hidden. 1570f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * @hide 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1572600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public Cursor rawQuery(String sql, String[] selectionArgs, 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int initialRead, int maxRead) { 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, sql, selectionArgs, null); 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.setLoadStyle(initialRead, maxRead); 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return c; 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1579600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insert(String table, String nullColumnHack, ContentValues values) { 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15948d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + values, e); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for inserting a row into the database. 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values this map contains the initial column values for the 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertOrThrow(String table, String nullColumnHack, ContentValues values) 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws SQLException { 16168d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE); 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replace(String table, String nullColumnHack, ContentValues initialValues) { 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1632600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 16338d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Error inserting " + initialValues, e); 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for replacing a row in the database. 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table in which to replace the row 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this row will explicitly be 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the row. The key 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the row ID of the newly inserted row, or -1 if an error occurred 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long replaceOrThrow(String table, String nullColumnHack, 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues initialValues) throws SQLException { 1654600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov return insertWithOnConflict(table, nullColumnHack, initialValues, 16558d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori CONFLICT_REPLACE); 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * General method for inserting a row into the database. 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to insert the row into 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param nullColumnHack SQL doesn't allow inserting a completely empty row, 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so if initialValues is empty this column will explicitly be 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * assigned a NULL value 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param initialValues this map contains the initial column values for the 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * row. The keys should be the column names and the values the 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * column values 16688d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for insert conflict resolver 16696eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * @return the row ID of the newly inserted row 16706eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR the primary key of the existing row if the input param 'conflictAlgorithm' = 16718d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * {@link #CONFLICT_IGNORE} 16726eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori * OR -1 if any error 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long insertWithOnConflict(String table, String nullColumnHack, 16756eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori ContentValues initialValues, int conflictAlgorithm) { 16760732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori StringBuilder sql = new StringBuilder(); 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("INSERT"); 16788d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" INTO "); 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 16810732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append('('); 16820732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori 16830732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori Object[] bindArgs = null; 16840732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0; 16850732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori if (size > 0) { 16860732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori bindArgs = new Object[size]; 16870732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori int i = 0; 16880732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori for (String colName : initialValues.keySet()) { 16890732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append((i > 0) ? "," : ""); 16900732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append(colName); 16910732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori bindArgs[i++] = initialValues.get(colName); 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(')'); 16940732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append(" VALUES ("); 16950732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori for (i = 0; i < size; i++) { 16960732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append((i > 0) ? ",?" : "?"); 16970732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori } 16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 16990732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append(nullColumnHack + ") VALUES (NULL"); 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17010732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append(')'); 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17030732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs); 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1705fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori return statement.executeInsert(); 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17100732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori statement.close(); 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for deleting rows in the database. 17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to delete from 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when deleting. 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will delete all rows. 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected if a whereClause is passed in, 0 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * otherwise. To remove all rows and get a count pass "1" as the 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * whereClause. 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int delete(String table, String whereClause, String[] whereArgs) { 17250732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table + 17260732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs); 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1728fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori return statement.executeUpdateDelete(); 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17330732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori statement.close(); 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { 17488d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE); 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1750600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Convenience method for updating rows in the database. 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param table the table to update in 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param values a map from column names to new column values. null is a 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * valid value that will be translated to NULL. 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param whereClause the optional WHERE clause to apply when updating. 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Passing null will update all rows. 17598d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori * @param conflictAlgorithm for update conflict resolver 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the number of rows affected 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1762600bdd82f58c7338e68ce2c8f04b17db4cf4f910Dmitri Plotnikov public int updateWithOnConflict(String table, ContentValues values, 17636eb7c45a8fdb774c4094b5012c8496f2a009c032Vasu Nori String whereClause, String[] whereArgs, int conflictAlgorithm) { 17640732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori int setValuesSize = values.size(); 17650732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori if (values == null || setValuesSize == 0) { 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty values"); 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sql = new StringBuilder(120); 17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("UPDATE "); 17718d45e4e4c6244cc3a508da3b56fec8cfd4cadd1dVasu Nori sql.append(CONFLICT_VALUES[conflictAlgorithm]); 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(table); 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" SET "); 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17750732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori // move all bind args to one array 17760732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length); 17770732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori Object[] bindArgs = new Object[bindArgsSize]; 17780732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori int i = 0; 17790732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori for (String colName : values.keySet()) { 17800732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append((i > 0) ? "," : ""); 17810732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori sql.append(colName); 17820732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori bindArgs[i++] = values.get(colName); 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append("=?"); 17840732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori } 17850732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori if (whereArgs != null) { 17860732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori for (i = setValuesSize; i < bindArgsSize; i++) { 17870732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori bindArgs[i] = whereArgs[i - setValuesSize]; 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!TextUtils.isEmpty(whereClause)) { 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(" WHERE "); 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sql.append(whereClause); 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17950732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs); 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1797fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori return statement.executeUpdateDelete(); 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 18020732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori statement.close(); 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1807ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Execute a single SQL statement that is NOT a SELECT 1808ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * or any other SQL statement that returns data. 1809ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1810ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori * It has no means to return any data (such as the number of affected rows). 1811ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)}, 1812ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * {@link #update(String, ContentValues, String, String[])}, et al, when possible. 1813ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 18149bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * <p> 18159bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * When using {@link #enableWriteAheadLogging()}, journal_mode is 18169bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * automatically managed by this class. So, do not set journal_mode 18179bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * using "PRAGMA journal_mode'<value>" statement if your app is using 18189bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * {@link #enableWriteAheadLogging()} 18199bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * </p> 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1821ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 1822ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * not supported. 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1825b83cb7cda3947fb35e126eab1530732fcd797ad0Vasu Nori public void execSQL(String sql) throws SQLException { 1826ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori int stmtType = DatabaseUtils.getSqlStatementType(sql); 1827ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (stmtType == DatabaseUtils.STATEMENT_ATTACH) { 18288d1110383d4437eeebae337026cd91449e4e55a5Vasu Nori disableWriteAheadLogging(); 18298d1110383d4437eeebae337026cd91449e4e55a5Vasu Nori } 1830c8e1f23891cff31a9da2bab412631ff770a92f56Vasu Nori long timeStart = SystemClock.uptimeMillis(); 1831722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX); 1832b83cb7cda3947fb35e126eab1530732fcd797ad0Vasu Nori executeSql(sql, null); 1833b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1834b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Log commit statements along with the most recently executed 1835ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori // SQL statement for disambiguation. 1836ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (stmtType == DatabaseUtils.STATEMENT_COMMIT) { 1837722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL); 1838b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } else { 1839722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(sql, timeStart, null); 1840b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick } 18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1844ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE. 1845ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1846ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For INSERT statements, use any of the following instead. 1847ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1848ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insert(String, String, ContentValues)}</li> 1849ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insertOrThrow(String, String, ContentValues)}</li> 1850ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li> 1851ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1852ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1853ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For UPDATE statements, use any of the following instead. 1854ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1855ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #update(String, ContentValues, String, String[])}</li> 1856ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li> 1857ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1858ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1859ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For DELETE statements, use any of the following instead. 1860ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1861ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>{@link #delete(String, String, String[])}</li> 1862ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1863ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <p> 1864ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * For example, the following are good candidates for using this method: 1865ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <ul> 1866ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>ALTER TABLE</li> 1867ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>CREATE or DROP table / trigger / view / index / virtual table</li> 1868ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>REINDEX</li> 1869ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>RELEASE</li> 1870ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>SAVEPOINT</li> 1871ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * <li>PRAGMA that returns no data</li> 1872ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </ul> 1873ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * </p> 18749bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * <p> 18759bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * When using {@link #enableWriteAheadLogging()}, journal_mode is 18769bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * automatically managed by this class. So, do not set journal_mode 18779bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * using "PRAGMA journal_mode'<value>" statement if your app is using 18789bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * {@link #enableWriteAheadLogging()} 18799bf225ef7b82b5eacee1907155a8a8bbb6aa7f42Vasu Nori * </p> 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1881ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 1882ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * not supported. 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bindArgs only byte[], String, Long and Double are supported in bindArgs. 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException If the SQL string is invalid for some reason 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1886b83cb7cda3947fb35e126eab1530732fcd797ad0Vasu Nori public void execSQL(String sql, Object[] bindArgs) throws SQLException { 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bindArgs == null) { 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Empty bindArgs"); 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1890b83cb7cda3947fb35e126eab1530732fcd797ad0Vasu Nori executeSql(sql, bindArgs); 1891ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 1892ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori 18935402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori private int executeSql(String sql, Object[] bindArgs) throws SQLException { 1894d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long timeStart = SystemClock.uptimeMillis(); 18955402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori int n; 18960732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs); 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18985402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori n = statement.executeUpdateDelete(); 18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLiteDatabaseCorruptException e) { 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onCorruption(); 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw e; 19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 19030732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori statement.close(); 19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 190512311959c6ec6898e3b40d4e8958b29ec0b72da9Dan Egnor logTimeStat(sql, timeStart); 19065402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori return n; 19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19109d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood protected void finalize() throws Throwable { 19119d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood try { 19129d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood if (isOpen()) { 19139d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood Log.e(TAG, "close() was never explicitly called on database '" + 19149d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood mPath + "' ", mStackTrace); 19159d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood closeClosable(); 19169d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood onAllReferencesReleased(); 19179d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood releaseCustomFunctions(); 19189d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } 19199d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood } finally { 19209d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood super.finalize(); 19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19252134369e803e944af84e73dcaf9356609a5481c6Vasu Nori * Private constructor. 19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param factory The factory to use when creating cursors, may be NULL. 19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already 19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * exists, mFlags will be updated appropriately. 19312134369e803e944af84e73dcaf9356609a5481c6Vasu Nori * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite reports database 19322134369e803e944af84e73dcaf9356609a5481c6Vasu Nori * corruption. may be NULL. 19336c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * @param connectionNum 0 for main database connection handle. 1..N for pooled database 19346c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * connection handles. 19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19362134369e803e944af84e73dcaf9356609a5481c6Vasu Nori private SQLiteDatabase(String path, CursorFactory factory, int flags, 19376c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori DatabaseErrorHandler errorHandler, short connectionNum) { 19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null) { 19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("path should not be null"); 19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFlags = flags; 19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 194390142c959e6de38eae1563cd8b3d2d448393e15fDmitri Plotnikov mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1); 194408b448ea39e9fabfc5212ae6f7226eba4385d189Vasu Nori mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace(); 19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFactory = factory; 19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPrograms = new WeakHashMap<SQLiteClosable,Object>(); 19472134369e803e944af84e73dcaf9356609a5481c6Vasu Nori // Set the DatabaseErrorHandler to be used when SQLite reports corruption. 19482134369e803e944af84e73dcaf9356609a5481c6Vasu Nori // If the caller sets errorHandler = null, then use default errorhandler. 19492134369e803e944af84e73dcaf9356609a5481c6Vasu Nori mErrorHandler = (errorHandler == null) ? new DefaultDatabaseErrorHandler() : errorHandler; 19506c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori mConnectionNum = connectionNum; 19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return whether the DB is opened as read only. 19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if DB is opened as read only 19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isReadOnly() { 19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mFlags & OPEN_READ_MASK) == OPEN_READONLY; 19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the DB is currently open (has not been closed) 19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isOpen() { 19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mNativeHandle != 0; 19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean needUpgrade(int newVersion) { 19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return newVersion > getVersion(); 19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Getter for the path to the database file. 19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the path to our database file. 19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final String getPath() { 19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPath; 19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1981d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick /* package */ void logTimeStat(String sql, long beginMillis) { 1982722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick logTimeStat(sql, beginMillis, null); 1983722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 1984722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 1985722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick /* package */ void logTimeStat(String sql, long beginMillis, String prefix) { 1986b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // Keep track of the last statement executed here, as this is 1987b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // the common funnel through which all methods of hitting 1988b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick // libsqlite eventually flow. 1989b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick mLastSqlStatement = sql; 1990b28c7972bd3e5e34138e2fd7a2e1433d65205bdfBrad Fitzpatrick 1991e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sample fast queries in proportion to the time taken. 1992e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Quantize the % first, so the logged sampling probability 1993e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // exactly equals the actual sampling rate for this query. 1994e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 1995e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori int samplePercent; 1996d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick long durationMillis = SystemClock.uptimeMillis() - beginMillis; 1997722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (durationMillis == 0 && prefix == GET_LOCK_LOG_PREFIX) { 1998722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // The common case is locks being uncontended. Don't log those, 1999722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // even at 1%, which is our default below. 2000722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick return; 2001722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 2002722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (sQueryLogTimeInMillis == 0) { 2003722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick sQueryLogTimeInMillis = SystemProperties.getInt("db.db_operation.threshold_ms", 500); 2004722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 2005722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (durationMillis >= sQueryLogTimeInMillis) { 2006e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori samplePercent = 100; 2007fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori } else { 2008722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1; 2009e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (mRandom.nextInt(100) >= samplePercent) return; 20105a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 2011e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 2012722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // Note: the prefix will be "COMMIT;" or "GETLOCK:" when non-null. We wait to do 2013722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick // it here so we avoid allocating in the common case. 2014722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick if (prefix != null) { 2015722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick sql = prefix + sql; 2016722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick } 2017722802e76b8805da523a612ad3482450fd327db0Brad Fitzpatrick 2018e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH); 2019e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 2020e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // ActivityThread.currentPackageName() only returns non-null if the 2021e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // current thread is an application main thread. This parameter tells 2022e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // us whether an event loop is blocked, and if so, which app it is. 2023e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // 2024e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Sadly, there's no fast way to determine app name if this is *not* a 2025e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // main thread, or when we are invoked via Binder (e.g. ContentProvider). 2026e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori // Hopefully the full path to the database will be informative enough. 2027e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 202801e4cfc47d0a2c7e7ab383d2fb23224ec52c0301Dianne Hackborn String blockingPackage = AppGlobals.getInitialPackage(); 2029e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori if (blockingPackage == null) blockingPackage = ""; 2030e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori 2031d72f718c9cc4bd5e4701f4c5cdab51b4d8cf6435Brad Fitzpatrick EventLog.writeEvent( 2032d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick EVENT_DB_OPERATION, 2033d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick getPathForLogs(), 2034d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick sql, 2035d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick durationMillis, 2036d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick blockingPackage, 2037d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick samplePercent); 2038d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 2039d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick 2040d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick /** 2041d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * Removes email addresses from database filenames before they're 2042d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * logged to the EventLog where otherwise apps could potentially 2043d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick * read them. 2044d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick */ 2045d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick private String getPathForLogs() { 2046d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPathForLogs != null) { 2047d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 2048d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 2049d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath == null) { 2050d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return null; 2051d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 2052d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick if (mPath.indexOf('@') == -1) { 2053d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = mPath; 2054d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } else { 2055d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick mPathForLogs = EMAIL_IN_DB_PATTERN.matcher(mPath).replaceAll("XX@YY"); 2056d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick } 2057d833023307494d5bfe3fdc1ce79761fb8c9f49a6Brad Fitzpatrick return mPathForLogs; 20585a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20595a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 20605a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori /** 2061e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * Sets the locale for this database. Does nothing if this database has 2062e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * the NO_LOCALIZED_COLLATORS flag set or was opened read only. 2063e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * @throws SQLException if the locale could not be set. The most common reason 2064e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * for this is that there is no collator available for the locale you requested. 2065e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * In this case the database remains unchanged. 20665a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori */ 2067e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori public void setLocale(Locale locale) { 2068e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori lock(); 2069e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori try { 2070e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori native_setLocale(locale.toString(), mFlags); 2071e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori } finally { 2072e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori unlock(); 20735a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20745a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori } 20755a03f36ef845f73eb4473193dbb0f93dd12a51afVasu Nori 2076ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* package */ void verifyDbIsOpen() { 20779463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori if (!isOpen()) { 20787501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori throw new IllegalStateException("database " + getPath() + " (conn# " + 20797501010b71d57264a06f82937f5fb29cb9f4b509Vasu Nori mConnectionNum + ") already closed"); 20809463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 2081ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori } 2082ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori 2083ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori /* package */ void verifyLockOwner() { 2084ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 2085ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori if (mLockingEnabled && !isDbLockedByCurrentThread()) { 20869463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori throw new IllegalStateException("Don't have database lock!"); 20879463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 20889463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori } 20899463f297ef51bd056626d0fb0708c83509f7ebd9Vasu Nori 2090b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /** 2091b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the 2092b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * cache of compiledQueries attached to 'this'. 2093b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * <p> 2094b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL, 2095b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current 2096b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * mapping is NOT replaced with the new mapping). 2097b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori */ 2098b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) { 2099b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori synchronized(mCompiledQueries) { 2100b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori // don't insert the new mapping if a mapping already exists 2101b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori if (mCompiledQueries.containsKey(sql)) { 2102b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori return; 2103b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2104b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 21055e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori if (!isCacheFullWarningLogged() && mCompiledQueries.size() == mMaxSqlCacheSize) { 2106b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* 2107b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * cache size of {@link #mMaxSqlCacheSize} is not enough for this app. 2108b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * log a warning. 2109b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * chances are it is NOT using ? for bindargs - or cachesize is too small. 2110b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori */ 21115e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " + 21125e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori getPath() + ". Use setMaxSqlCacheSize() to increase cachesize. "); 21135e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori setCacheFullWarningLogged(); 2114b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2115b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* add the given SQLiteCompiledSql compiledStatement to cache. 2116b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * no need to worry about the cache size - because {@link #mCompiledQueries} 2117b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * self-limits its size to {@link #mMaxSqlCacheSize}. 2118b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori */ 2119b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori mCompiledQueries.put(sql, compiledStatement); 2120b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2121b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2122b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 2123b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /** package-level access for testing purposes */ 2124b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* package */ void deallocCachedSqlStatements() { 2125b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori synchronized (mCompiledQueries) { 2126b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) { 2127b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori compiledSql.releaseSqlStatement(); 2128b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2129b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori mCompiledQueries.clear(); 2130b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2131b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2132b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 2133b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /** 2134b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * From the compiledQueries cache, returns the compiled-statement-id for the given SQL. 2135b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * Returns null, if not found in the cache. 2136b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori */ 21375e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori /* package */ synchronized SQLiteCompiledSql getCompiledStatementForSql(String sql) { 21385e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori SQLiteCompiledSql compiledStatement = mCompiledQueries.get(sql); 21395e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori if (compiledStatement == null) { 2140b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori mNumCacheMisses++; 21415e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori return null; 2142b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 21435e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori mNumCacheHits++; 2144b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori return compiledStatement; 2145b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2146b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 2147e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori /** 2148ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Sets the maximum size of the prepared-statement cache for this database. 2149e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * (size of the cache = number of compiled-sql-statements stored in the cache). 2150ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2151b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * Maximum cache size can ONLY be increased from its current size (default = 10). 2152ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * If this method is called with smaller size than the current maximum value, 2153ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * then IllegalStateException is thrown. 2154b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori *<p> 2155b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori * This method is thread-safe. 2156e495d1f74af13aec8d5d825e93e4cfe1e4fe7468Vasu Nori * 215790a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE}) 215890a36726b7553a1e7efd2f4ecbe01d7e1b3e7a67Vasu Nori * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or 2159bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * the value set with previous setMaxSqlCacheSize() call. 21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21615402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori public void setMaxSqlCacheSize(int cacheSize) { 21625402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori synchronized(this) { 21635402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) { 21645402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE); 21655402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori } else if (cacheSize < mMaxSqlCacheSize) { 21665402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori throw new IllegalStateException("cannot set cacheSize to a value less than the value " + 21675402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori "set with previous setMaxSqlCacheSize() call."); 21685402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori } 21695402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori mMaxSqlCacheSize = cacheSize; 2170b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2171b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 2172b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori 2173b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori /* package */ boolean isSqlInStatementCache(String sql) { 2174b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori synchronized (mCompiledQueries) { 2175b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori return mCompiledQueries.containsKey(sql); 2176b729dcc8a94bc2c2a1ecda47d791be0d6f1d160aVasu Nori } 21776c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 21786c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 21795e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private synchronized boolean isCacheFullWarningLogged() { 21805e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori return mCacheFullWarning; 21815e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori } 21825e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori 21835e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private synchronized void setCacheFullWarningLogged() { 21845e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori mCacheFullWarning = true; 21855e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori } 21865e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori 21875e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private synchronized int getCacheHitNum() { 21885e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori return mNumCacheHits; 21895e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori } 21905e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori 21915e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private synchronized int getCacheMissNum() { 21925e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori return mNumCacheMisses; 21935e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori } 21945e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori 21955e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori private synchronized int getCachesize() { 21965e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori return mCompiledQueries.size(); 21975e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori } 21985e89ae29f0e8bf71d54360d35243da905892b168Vasu Nori 21996f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* package */ void finalizeStatementLater(int id) { 22006f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (!isOpen()) { 22016f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // database already closed. this statement will already have been finalized. 22026f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 22036f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22046f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori synchronized(mClosedStatementIds) { 22056f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (mClosedStatementIds.contains(id)) { 22066f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // this statement id is already queued up for finalization. 22076f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 22086f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22096f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.add(id); 22106f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22116f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22126f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 2213ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /* package */ void closePendingStatements() { 22146f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori if (!isOpen()) { 22156f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // since this database is already closed, no need to finalize anything. 22166f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.clear(); 22176f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return; 22186f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22196f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori verifyLockOwner(); 22206f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /* to minimize synchronization on mClosedStatementIds, make a copy of the list */ 22216f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori ArrayList<Integer> list = new ArrayList<Integer>(mClosedStatementIds.size()); 22226f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori synchronized(mClosedStatementIds) { 22236f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori list.addAll(mClosedStatementIds); 22246f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori mClosedStatementIds.clear(); 22256f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22266f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori // finalize all the statements from the copied list 22276f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori int size = list.size(); 22286f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori for (int i = 0; i < size; i++) { 22296f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori native_finalize(list.get(i)); 22306f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22316f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22326f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 22336f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** 22346f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * for testing only 22356f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori */ 2236ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori /* package */ ArrayList<Integer> getQueuedUpStmtList() { 22376f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori return mClosedStatementIds; 22386f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori } 22396f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 22406c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** 22416c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * This method enables parallel execution of queries from multiple threads on the same database. 22426c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * It does this by opening multiple handles to the database and using a different 22436c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * database handle for each query. 22446c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22456c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * If a transaction is in progress on one connection handle and say, a table is updated in the 22466c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * transaction, then query on the same table on another connection handle will block for the 22476c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * transaction to complete. But this method enables such queries to execute by having them 22486c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * return old version of the data from the table. Most often it is the data that existed in the 22496c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * table prior to the above transaction updates on that table. 22506c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22516c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Maximum number of simultaneous handles used to execute queries in parallel is 22526c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * dependent upon the device memory and possibly other properties. 22536c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22546c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * After calling this method, execution of queries in parallel is enabled as long as this 22556c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * database handle is open. To disable execution of queries in parallel, database should 22566c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * be closed and reopened. 22576c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22586c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * If a query is part of a transaction, then it is executed on the same database handle the 22596c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * transaction was begun. 22606c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22616c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * If the database has any attached databases, then execution of queries in paralel is NOT 2262a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori * possible. In such cases, a message is printed to logcat and false is returned. 2263a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori * <p> 2264a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori * This feature is not available for :memory: databases. In such cases, 2265a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori * a message is printed to logcat and false is returned. 22666c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22676c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * A typical way to use this method is the following: 22686c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <pre> 22696c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, 22706c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * CREATE_IF_NECESSARY, myDatabaseErrorHandler); 22716c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * db.enableWriteAheadLogging(); 22726c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * </pre> 22736c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 22746c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Writers should use {@link #beginTransactionNonExclusive()} or 22756c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)} 22766c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * to start a trsnsaction. 22776c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Non-exclusive mode allows database file to be in readable by threads executing queries. 22786c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * </p> 22796c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * 2280a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori * @return true if write-ahead-logging is set. false otherwise 22816c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 2282a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori public synchronized boolean enableWriteAheadLogging() { 2283a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori if (mPath.equalsIgnoreCase(MEMORY_DB_PATH)) { 2284a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori Log.i(TAG, "can't enable WAL for memory databases."); 2285a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori return false; 22866c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 22876c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 22886c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // make sure this database has NO attached databases because sqlite's write-ahead-logging 22896c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // doesn't work for databases with attached databases 22906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (getAttachedDbs().size() > 1) { 2291ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 2292ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.d(TAG, 2293ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori "this database: " + mPath + " has attached databases. can't enable WAL."); 2294ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori } 2295a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori return false; 22966c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 2297a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori if (mConnectionPool == null) { 2298a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori mConnectionPool = new DatabaseConnectionPool(this); 2299a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori setJournalMode(mPath, "WAL"); 23006c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 2301a98cb2632dcf07ebd8d036f61c1438f795e262ccVasu Nori return true; 23026c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 23036c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 23042827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori /** 23057b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori * This method disables the features enabled by {@link #enableWriteAheadLogging()}. 23067b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori * @hide 23072827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori */ 23087b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori public void disableWriteAheadLogging() { 23097b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori synchronized (this) { 23107b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori if (mConnectionPool == null) { 23117b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori return; 23127b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori } 23137b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori mConnectionPool.close(); 23147b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori mConnectionPool = null; 23157b04c4176d9cb2f96487ad891f4cf769bccb4f1bVasu Nori setJournalMode(mPath, "TRUNCATE"); 23168d1110383d4437eeebae337026cd91449e4e55a5Vasu Nori } 23178d1110383d4437eeebae337026cd91449e4e55a5Vasu Nori } 23188d1110383d4437eeebae337026cd91449e4e55a5Vasu Nori 231965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori /* package */ SQLiteDatabase getDatabaseHandle(String sql) { 232065a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori if (isPooledConnection()) { 232165a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // this is a pooled database connection 2322ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori // use it if it is open AND if I am not currently part of a transaction 2323ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (isOpen() && !amIInTransaction()) { 232465a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // TODO: use another connection from the pool 232565a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // if this connection is currently in use by some other thread 232665a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // AND if there are free connections in the pool 232765a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return this; 232865a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } else { 232965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // the pooled connection is not open! could have been closed either due 233065a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // to corruption on this or some other connection to the database 233165a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // OR, maybe the connection pool is disabled after this connection has been 233265a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // allocated to me. try to get some other pooled or main database connection 233365a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return getParentDbConnObj().getDbConnection(sql); 233465a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } 233565a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } else { 233665a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // this is NOT a pooled connection. can we get one? 233765a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return getDbConnection(sql); 233865a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } 233965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } 234065a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori 23416c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /** 23426c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Sets the database connection handle pool size to the given value. 23436c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * Database connection handle pool is enabled when the app calls 23446c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * {@link #enableWriteAheadLogging()}. 23456c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * <p> 23466c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * The default connection handle pool is set by the system by taking into account various 23476c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * aspects of the device, such as memory, number of cores etc. It is recommended that 23486c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * applications use the default pool size set by the system. 23496c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * 23506c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * @param size the value the connection handle pool size should be set to. 23516c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori */ 23525402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori public void setConnectionPoolSize(int size) { 23535402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori synchronized(this) { 23545402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori if (mConnectionPool == null) { 23555402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori throw new IllegalStateException("connection pool not enabled"); 23565402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori } 23575402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori int i = mConnectionPool.getMaxPoolSize(); 23585402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori if (size < i) { 23595402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori throw new IllegalArgumentException( 23605402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori "cannot set max pool size to a value less than the current max value(=" + 23615402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori i + ")"); 23625402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori } 23635402590f1cb8ae1bc31f796705ff6f10bc175730Vasu Nori mConnectionPool.setMaxPoolSize(size); 23646c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 23656c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 23666c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 23676c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori /* package */ SQLiteDatabase createPoolConnection(short connectionNum) { 236865a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori SQLiteDatabase db = openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum); 236965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori db.mParentConnObj = this; 237065a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return db; 237165a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } 237265a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori 237365a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori private synchronized SQLiteDatabase getParentDbConnObj() { 237465a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return mParentConnObj; 23756c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 23766c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 23776c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private boolean isPooledConnection() { 23786c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori return this.mConnectionNum > 0; 23796c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 23806c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 23812827d6d974beabb12344040a002dcb52dd7106b5Vasu Nori /* package */ SQLiteDatabase getDbConnection(String sql) { 23826c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori verifyDbIsOpen(); 2383bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori // this method should always be called with main database connection handle. 2384bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori // the only time when it is called with pooled database connection handle is 2385bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori // corruption occurs while trying to open a pooled database connection handle. 2386bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori // in that case, simply return 'this' handle 238765a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori if (isPooledConnection()) { 2388bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori return this; 238965a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori } 23906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 23916c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // use the current connection handle if 2392ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori // 1. if the caller is part of the ongoing transaction, if any 239365a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori // 2. OR, if there is NO connection handle pool setup 2394ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori if (amIInTransaction() || mConnectionPool == null) { 239565a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return this; 23966c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } else { 23976c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // get a connection handle from the pool 23986c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 23996c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori assert mConnectionPool != null; 2400ce38b98feb1e7c9c1799eb270c40798d833aa9aeVasu Nori Log.i(TAG, mConnectionPool.toString()); 24016c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 240265a8883f0e605bb8a73a692987b47ce5da632e72Vasu Nori return mConnectionPool.get(sql); 24036c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 24046c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 24056c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 24066c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private void releaseDbConnection(SQLiteDatabase db) { 24076c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // ignore this release call if 24086c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // 1. the database is closed 24096c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // 2. OR, if db is NOT a pooled connection handle 24106c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // 3. OR, if the database being released is same as 'this' (this condition means 24116c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // that we should always be releasing a pooled connection handle by calling this method 24126c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori // from the 'main' connection handle 24136c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (!isOpen() || !db.isPooledConnection() || (db == this)) { 24146c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori return; 24156c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 24166c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori if (Log.isLoggable(TAG, Log.DEBUG)) { 24176c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori assert isPooledConnection(); 24186c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori assert mConnectionPool != null; 24196c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori Log.d(TAG, "releaseDbConnection threadid = " + Thread.currentThread().getId() + 24206c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori ", releasing # " + db.mConnectionNum + ", " + getPath()); 24216c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 24226c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori mConnectionPool.release(db); 24236c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori } 24246c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori 2425f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori /** 2426f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori * this method is used to collect data about ALL open databases in the current process. 24270732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori * bugreport is a user of this data. 2428f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori */ 2429c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori /* package */ static ArrayList<DbStats> getDbStats() { 2430c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>(); 24315a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // make a local copy of mActiveDatabases - so that this method is not competing 24325a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // for synchronization lock on mActiveDatabases 24335a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// ArrayList<WeakReference<SQLiteDatabase>> tempList; 24345a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// synchronized(mActiveDatabases) { 24355a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// tempList = (ArrayList<WeakReference<SQLiteDatabase>>)mActiveDatabases.clone(); 24365a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24375a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// for (WeakReference<SQLiteDatabase> w : tempList) { 24385a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// SQLiteDatabase db = w.get(); 24395a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (db == null || !db.isOpen()) { 24405a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// continue; 24415a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24425a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// 24435a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// synchronized (db) { 24445a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// try { 24455a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db 24465a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// int lookasideUsed = db.native_getDbLookaside(); 24475a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// 24485a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // get the lastnode of the dbname 24495a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// String path = db.getPath(); 24505a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// int indx = path.lastIndexOf("/"); 24515a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// String lastnode = path.substring((indx != -1) ? ++indx : 0); 24525a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// 24535a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // get list of attached dbs and for each db, get its size and pagesize 24545a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); 24555a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (attachedDbs == null) { 24565a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// continue; 24575a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24585a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// for (int i = 0; i < attachedDbs.size(); i++) { 24595a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// Pair<String, String> p = attachedDbs.get(i); 24605a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first 24615a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// + ".page_count;", null); 24625a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// 24635a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // first entry in the attached db list is always the main database 24645a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // don't worry about prefixing the dbname with "main" 24655a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// String dbName; 24665a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (i == 0) { 24675a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// dbName = lastnode; 24685a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } else { 24695a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // lookaside is only relevant for the main db 24705a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// lookasideUsed = 0; 24715a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// dbName = " (attached) " + p.first; 24725a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // if the attached db has a path, attach the lastnode from the path to above 24735a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (p.second.trim().length() > 0) { 24745a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// int idx = p.second.lastIndexOf("/"); 24755a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); 24765a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24775a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24785a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (pageCount > 0) { 24795a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), 24805a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// lookasideUsed, db.getCacheHitNum(), db.getCacheMissNum(), 24815a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// db.getCachesize())); 24825a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24835a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24845a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // if there are pooled connections, return the cache stats for them also. 24855a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// if (db.mConnectionPool != null) { 24865a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) { 24875a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") " 24885a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// + lastnode, 0, 0, 0, pDb.getCacheHitNum(), 24895a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// pDb.getCacheMissNum(), pDb.getCachesize())); 24905a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24915a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24925a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } catch (SQLiteException e) { 24935a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // ignore. we don't care about exceptions when we are taking adb 24945a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// // bugreport! 24955a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24965a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 24975a049b0fffd98f5b6b61e43a01345c476d27c1f7Vasu Nori// } 2498c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return dbStatsList; 2499c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2500c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 2501c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori /** 2502ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Returns list of full pathnames of all attached databases including the main database 2503ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * by executing 'pragma database_list' on the database. 2504ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * 2505062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * @return ArrayList of pairs of (database name, database file path) or null if the database 2506062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * is not open. 2507c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori */ 2508062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public ArrayList<Pair<String, String>> getAttachedDbs() { 2509062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (!isOpen()) { 2510f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori return null; 2511f3cf8a4da8ef28e62586cc07edce99879e2c3a56Vasu Nori } 2512c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>(); 2513062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Cursor c = null; 2514062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 2515062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori c = rawQuery("pragma database_list;", null); 2516062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori while (c.moveToNext()) { 2517062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // sqlite returns a row for each database in the returned list of databases. 2518062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // in each row, 2519062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // 1st column is the database name such as main, or the database 2520062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // name specified on the "ATTACH" command 2521062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // 2nd column is the database file path. 2522062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2))); 2523062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2524062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } finally { 2525062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (c != null) { 2526062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori c.close(); 2527062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2528c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2529c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori return attachedDbs; 2530c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori } 2531c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori 25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2533ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Runs 'pragma integrity_check' on the given database (and all the attached databases) 2534ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * and returns true if the given database (and all its attached databases) pass integrity_check, 2535062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * false otherwise. 2536ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2537ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * If the result is false, then this method logs the errors reported by the integrity_check 2538062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * command execution. 2539ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori *<p> 2540ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Note that 'pragma integrity_check' on a database can take a long time. 2541062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * 2542062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori * @return true if the given database (and all its attached databases) pass integrity_check, 2543ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * false otherwise. 2544062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori */ 2545062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori public boolean isDatabaseIntegrityOk() { 2546ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori verifyDbIsOpen(); 2547bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori ArrayList<Pair<String, String>> attachedDbs = null; 2548bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori try { 2549bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori attachedDbs = getAttachedDbs(); 2550bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori if (attachedDbs == null) { 2551bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " + 2552bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori "be retrieved. probably because the database is closed"); 2553bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori } 2554bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori } catch (SQLiteException e) { 2555bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori // can't get attachedDb list. do integrity check on the main database 2556bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori attachedDbs = new ArrayList<Pair<String, String>>(); 2557bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori attachedDbs.add(new Pair<String, String>("main", this.mPath)); 2558062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2559062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori for (int i = 0; i < attachedDbs.size(); i++) { 2560062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Pair<String, String> p = attachedDbs.get(i); 2561062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori SQLiteStatement prog = null; 2562062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori try { 2563062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);"); 2564062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori String rslt = prog.simpleQueryForString(); 2565062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (!rslt.equalsIgnoreCase("ok")) { 2566062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori // integrity_checker failed on main or attached databases 2567062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt); 2568bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori return false; 2569062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2570062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } finally { 2571062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori if (prog != null) prog.close(); 2572062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2573062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2574bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori return true; 2575062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori } 2576062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori 2577062fc7ce369758d5a26f83f12b50b11cd88e5defVasu Nori /** 25789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to open the database. 25799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 25809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param path The full path to the database 25819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 25829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void dbopen(String path, int flags); 25839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2585ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Native call to setup tracing of all SQL statements 25863ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 25873ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 25886c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * @param connectionNum connection number: 0 - N, where the main database 25896c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * connection handle is numbered 0 and the connection handles in the connection 25906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * pool are numbered 1..N. 25913ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 25926c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private native void enableSqlTracing(String path, short connectionNum); 25933ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 25943ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 2595ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * Native call to setup profiling of all SQL statements. 25963ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * currently, sqlite's profiling = printing of execution-time 2597ccd954480c32e9f35357b66023ae912e7f3fa76bVasu Nori * (wall-clock time) of each of the SQL statements, as they 25983ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * are executed. 25993ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * 26003ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori * @param path the full path to the database 26016c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * @param connectionNum connection number: 0 - N, where the main database 26026c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * connection handle is numbered 0 and the connection handles in the connection 26036c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori * pool are numbered 1..N. 26043ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori */ 26056c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori private native void enableSqlProfiling(String path, short connectionNum); 26063ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori 26073ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori /** 26089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Native call to set the locale. {@link #lock} must be held when calling 26099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this method. 26109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws SQLException 26119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 26120732f7912ccec9a1cc379b535ac0b56ae50972b3Vasu Nori private native void native_setLocale(String loc, int flags); 26139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2615c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here 2616c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html 2617c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED 2618c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori */ 2619c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori private native int native_getDbLookaside(); 26206f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori 26216f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori /** 26226f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * finalizes the given statement id. 26236f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * 26246f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori * @param statementId statement to be finzlied by sqlite 26256f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori */ 26266f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori private final native void native_finalize(int statementId); 26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2628