blob: 6882ea2116cda372181d6cc45bf2beead4f07696 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.database.sqlite;
18
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070019import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.ContentValues;
21import android.database.Cursor;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070022import android.database.DatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.database.DatabaseUtils;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070024import android.database.DefaultDatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.database.SQLException;
Vasu Noric3849202010-03-09 10:47:25 -080026import android.database.sqlite.SQLiteDebug.DbStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.os.Debug;
Vasu Noria8c24902010-06-01 11:30:27 -070028import android.os.StatFs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.SystemClock;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070030import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.text.TextUtils;
32import android.util.Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.EventLog;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070034import android.util.Log;
Vasu Noric3849202010-03-09 10:47:25 -080035import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -070037import dalvik.system.BlockGuard;
38
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import java.io.File;
Vasu Noric3849202010-03-09 10:47:25 -080040import java.lang.ref.WeakReference;
Vasu Noric3849202010-03-09 10:47:25 -080041import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.util.HashMap;
43import java.util.Iterator;
Vasu Norib729dcc2010-09-14 11:35:49 -070044import java.util.LinkedHashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import java.util.Locale;
46import java.util.Map;
Dan Egnor12311952009-11-23 14:47:45 -080047import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import java.util.WeakHashMap;
49import java.util.concurrent.locks.ReentrantLock;
Brad Fitzpatrickd8330232010-02-19 10:59:01 -080050import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
52/**
53 * Exposes methods to manage a SQLite database.
54 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
55 * perform other common database management tasks.
56 * <p>See the Notepad sample application in the SDK for an example of creating
57 * and managing a database.
58 * <p> Database names must be unique within an application, not across all
59 * applications.
60 *
61 * <h3>Localized Collation - ORDER BY</h3>
62 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
63 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
64 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
65 * is the Unicode Collation Algorithm and not tailored to the current locale.
66 */
67public class SQLiteDatabase extends SQLiteClosable {
Vasu Norifb16cbd2010-07-25 16:38:48 -070068 private static final String TAG = "SQLiteDatabase";
Jeff Hamilton082c2af2009-09-29 11:49:51 -070069 private static final int EVENT_DB_OPERATION = 52000;
70 private static final int EVENT_DB_CORRUPT = 75004;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72 /**
73 * Algorithms used in ON CONFLICT clause
74 * http://www.sqlite.org/lang_conflict.html
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 */
Vasu Nori8d45e4e2010-02-05 22:35:47 -080076 /**
77 * When a constraint violation occurs, an immediate ROLLBACK occurs,
78 * thus ending the current transaction, and the command aborts with a
79 * return code of SQLITE_CONSTRAINT. If no transaction is active
80 * (other than the implied transaction that is created on every command)
81 * then this algorithm works the same as ABORT.
82 */
83 public static final int CONFLICT_ROLLBACK = 1;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070084
Vasu Nori8d45e4e2010-02-05 22:35:47 -080085 /**
86 * When a constraint violation occurs,no ROLLBACK is executed
87 * so changes from prior commands within the same transaction
88 * are preserved. This is the default behavior.
89 */
90 public static final int CONFLICT_ABORT = 2;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070091
Vasu Nori8d45e4e2010-02-05 22:35:47 -080092 /**
93 * When a constraint violation occurs, the command aborts with a return
94 * code SQLITE_CONSTRAINT. But any changes to the database that
95 * the command made prior to encountering the constraint violation
96 * are preserved and are not backed out.
97 */
98 public static final int CONFLICT_FAIL = 3;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070099
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800100 /**
101 * When a constraint violation occurs, the one row that contains
102 * the constraint violation is not inserted or changed.
103 * But the command continues executing normally. Other rows before and
104 * after the row that contained the constraint violation continue to be
105 * inserted or updated normally. No error is returned.
106 */
107 public static final int CONFLICT_IGNORE = 4;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700108
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800109 /**
110 * When a UNIQUE constraint violation occurs, the pre-existing rows that
111 * are causing the constraint violation are removed prior to inserting
112 * or updating the current row. Thus the insert or update always occurs.
113 * The command continues executing normally. No error is returned.
114 * If a NOT NULL constraint violation occurs, the NULL value is replaced
115 * by the default value for that column. If the column has no default
116 * value, then the ABORT algorithm is used. If a CHECK constraint
117 * violation occurs then the IGNORE algorithm is used. When this conflict
118 * resolution strategy deletes rows in order to satisfy a constraint,
119 * it does not invoke delete triggers on those rows.
120 * This behavior might change in a future release.
121 */
122 public static final int CONFLICT_REPLACE = 5;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700123
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800124 /**
125 * use the following when no conflict action is specified.
126 */
127 public static final int CONFLICT_NONE = 0;
128 private static final String[] CONFLICT_VALUES = new String[]
129 {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 /**
132 * Maximum Length Of A LIKE Or GLOB Pattern
133 * The pattern matching algorithm used in the default LIKE and GLOB implementation
134 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
135 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
136 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
137 * The default value of this limit is 50000. A modern workstation can evaluate
138 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
139 * The denial of service problem only comes into play when the pattern length gets
140 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
141 * are at most a few dozen bytes in length, paranoid application developers may
142 * want to reduce this parameter to something in the range of a few hundred
143 * if they know that external users are able to generate arbitrary patterns.
144 */
145 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
146
147 /**
148 * Flag for {@link #openDatabase} to open the database for reading and writing.
149 * If the disk is full, this may fail even before you actually write anything.
150 *
151 * {@more} Note that the value of this flag is 0, so it is the default.
152 */
153 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
154
155 /**
156 * Flag for {@link #openDatabase} to open the database for reading only.
157 * This is the only reliable way to open a database if the disk may be full.
158 */
159 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
160
161 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
162
163 /**
164 * Flag for {@link #openDatabase} to open the database without support for localized collators.
165 *
166 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
167 * You must be consistent when using this flag to use the setting the database was
168 * created with. If this is set, {@link #setLocale} will do nothing.
169 */
170 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
171
172 /**
173 * Flag for {@link #openDatabase} to create the database file if it does not already exist.
174 */
175 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
176
177 /**
178 * Indicates whether the most-recently started transaction has been marked as successful.
179 */
180 private boolean mInnerTransactionIsSuccessful;
181
182 /**
183 * Valid during the life of a transaction, and indicates whether the entire transaction (the
184 * outer one and all of the inner ones) so far has been successful.
185 */
186 private boolean mTransactionIsSuccessful;
187
Fred Quintanac4516a72009-09-03 12:14:06 -0700188 /**
189 * Valid during the life of a transaction.
190 */
191 private SQLiteTransactionListener mTransactionListener;
192
Vasu Norice38b982010-07-22 13:57:13 -0700193 /**
194 * this member is set if {@link #execSQL(String)} is used to begin and end transactions.
195 */
196 private boolean mTransactionUsingExecSql;
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 /** Synchronize on this when accessing the database */
199 private final ReentrantLock mLock = new ReentrantLock(true);
200
201 private long mLockAcquiredWallTime = 0L;
202 private long mLockAcquiredThreadTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 // limit the frequency of complaints about each database to one within 20 sec
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700205 // unless run command adb shell setprop log.tag.Database VERBOSE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
207 /** If the lock is held this long then a warning will be printed when it is released. */
208 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
209 private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
210 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
211
Dmitri Plotnikovb43b58d2009-09-09 18:10:42 -0700212 private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700213
Brad Fitzpatrickd8330232010-02-19 10:59:01 -0800214 // The pattern we remove from database filenames before
215 // potentially logging them.
216 private static final Pattern EMAIL_IN_DB_PATTERN = Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+");
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private long mLastLockMessageTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700219
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800220 // Things related to query logging/sampling for debugging
221 // slow/frequent queries during development. Always log queries
Brad Fitzpatrick722802e2010-03-23 22:22:16 -0700222 // which take (by default) 500ms+; shorter queries are sampled
223 // accordingly. Commit statements, which are typically slow, are
224 // logged together with the most recently executed SQL statement,
225 // for disambiguation. The 500ms value is configurable via a
226 // SystemProperty, but developers actively debugging database I/O
227 // should probably use the regular log tunable,
228 // LOG_SLOW_QUERIES_PROPERTY, defined below.
229 private static int sQueryLogTimeInMillis = 0; // lazily initialized
Dan Egnor12311952009-11-23 14:47:45 -0800230 private static final int QUERY_LOG_SQL_LENGTH = 64;
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800231 private static final String COMMIT_SQL = "COMMIT;";
Dan Egnor12311952009-11-23 14:47:45 -0800232 private final Random mRandom = new Random();
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800233 private String mLastSqlStatement = null;
Dan Egnor12311952009-11-23 14:47:45 -0800234
Brad Fitzpatrick722802e2010-03-23 22:22:16 -0700235 // String prefix for slow database query EventLog records that show
236 // lock acquistions of the database.
237 /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:";
238
Vasu Nori6f37f832010-05-19 11:53:25 -0700239 /** Used by native code, do not rename. make it volatile, so it is thread-safe. */
240 /* package */ volatile int mNativeHandle = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
Vasu Noria8c24902010-06-01 11:30:27 -0700242 /**
243 * The size, in bytes, of a block on "/data". This corresponds to the Unix
244 * statfs.f_bsize field. note that this field is lazily initialized.
245 */
246 private static int sBlockSize = 0;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 /** The path for the database file */
Vasu Noriccd95442010-05-28 17:04:16 -0700249 private final String mPath;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
Brad Fitzpatrickd8330232010-02-19 10:59:01 -0800251 /** The anonymized path for the database file for logging purposes */
252 private String mPathForLogs = null; // lazily populated
253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 /** The flags passed to open/create */
Vasu Noriccd95442010-05-28 17:04:16 -0700255 private final int mFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 /** The optional factory to use when creating new Cursors */
Vasu Noriccd95442010-05-28 17:04:16 -0700258 private final CursorFactory mFactory;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700259
Vasu Nori21343692010-06-03 16:01:39 -0700260 private final WeakHashMap<SQLiteClosable, Object> mPrograms;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700261
Vasu Nori5a03f362009-10-20 15:16:35 -0700262 /**
Vasu Norib729dcc2010-09-14 11:35:49 -0700263 * for each instance of this class, a LRU cache is maintained to store
264 * the compiled query statement ids returned by sqlite database.
265 * key = SQL statement with "?" for bind args
266 * value = {@link SQLiteCompiledSql}
267 * If an application opens the database and keeps it open during its entire life, then
268 * there will not be an overhead of compilation of SQL statements by sqlite.
269 *
270 * why is this cache NOT static? because sqlite attaches compiledsql statements to the
271 * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
272 * invoked.
273 *
274 * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
275 * (@link #setMaxSqlCacheSize(int)}).
276 */
277 // default statement-cache size per database connection ( = instance of this class)
278 private int mMaxSqlCacheSize = 25;
279 /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries =
280 new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) {
281 @Override
282 public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) {
283 // eldest = least-recently used entry
284 // if it needs to be removed to accommodate a new entry,
285 // close {@link SQLiteCompiledSql} represented by this entry, if not in use
286 // and then let it be removed from the Map.
287 // when this is called, the caller must be trying to add a just-compiled stmt
288 // to cache; i.e., caller should already have acquired database lock AND
289 // the lock on mCompiledQueries. do as assert of these two 2 facts.
290 verifyLockOwner();
291 if (this.size() <= mMaxSqlCacheSize) {
292 // cache is not full. nothing needs to be removed
293 return false;
294 }
295 // cache is full. eldest will be removed.
Vasu Nori5e89ae22010-09-15 14:23:29 -0700296 eldest.getValue().releaseIfNotInUse();
Vasu Norib729dcc2010-09-14 11:35:49 -0700297 // return true, so that this entry is removed automatically by the caller.
298 return true;
299 }
300 };
301 /**
302 * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}
303 * size of each prepared-statement is between 1K - 6K, depending on the complexity of the
Vasu Noriccd95442010-05-28 17:04:16 -0700304 * SQL statement & schema.
Vasu Norie495d1f2010-01-06 16:34:19 -0800305 */
Vasu Nori90a367262010-04-12 12:49:09 -0700306 public static final int MAX_SQL_CACHE_SIZE = 100;
Vasu Nori5e89ae22010-09-15 14:23:29 -0700307 private boolean mCacheFullWarning;
Vasu Norib729dcc2010-09-14 11:35:49 -0700308
309 /** maintain stats about number of cache hits and misses */
310 private int mNumCacheHits;
311 private int mNumCacheMisses;
Vasu Nori5a03f362009-10-20 15:16:35 -0700312
Vasu Norid606b4b2010-02-24 12:54:20 -0800313 /** Used to find out where this object was created in case it never got closed. */
Vasu Nori21343692010-06-03 16:01:39 -0700314 private final Throwable mStackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315
Dmitri Plotnikov90142c92009-09-15 10:52:17 -0700316 // System property that enables logging of slow queries. Specify the threshold in ms.
317 private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
318 private final int mSlowQueryThreshold;
319
Vasu Nori6f37f832010-05-19 11:53:25 -0700320 /** stores the list of statement ids that need to be finalized by sqlite */
Vasu Nori21343692010-06-03 16:01:39 -0700321 private final ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>();
Vasu Nori6f37f832010-05-19 11:53:25 -0700322
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700323 /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors
324 * Corruption
325 * */
Vasu Nori21343692010-06-03 16:01:39 -0700326 private final DatabaseErrorHandler mErrorHandler;
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700327
Vasu Nori6c354da2010-04-26 23:33:39 -0700328 /** The Database connection pool {@link DatabaseConnectionPool}.
329 * Visibility is package-private for testing purposes. otherwise, private visibility is enough.
330 */
331 /* package */ volatile DatabaseConnectionPool mConnectionPool = null;
332
333 /** Each database connection handle in the pool is assigned a number 1..N, where N is the
334 * size of the connection pool.
335 * The main connection handle to which the pool is attached is assigned a value of 0.
336 */
337 /* package */ final short mConnectionNum;
338
Vasu Nori65a88832010-07-16 15:14:08 -0700339 /** on pooled database connections, this member points to the parent ( = main)
340 * database connection handle.
341 * package visibility only for testing purposes
342 */
343 /* package */ SQLiteDatabase mParentConnObj = null;
344
Vasu Noria98cb262010-06-22 13:16:35 -0700345 private static final String MEMORY_DB_PATH = ":memory:";
346
Vasu Nori0732f792010-07-29 17:24:12 -0700347 /** stores reference to all databases opened in the current process. */
348 private static ArrayList<WeakReference<SQLiteDatabase>> mActiveDatabases =
349 new ArrayList<WeakReference<SQLiteDatabase>>();
350
Vasu Nori2827d6d2010-07-04 00:26:18 -0700351 synchronized void addSQLiteClosable(SQLiteClosable closable) {
352 // mPrograms is per instance of SQLiteDatabase and it doesn't actually touch the database
353 // itself. so, there is no need to lock().
354 mPrograms.put(closable, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700356
Vasu Nori2827d6d2010-07-04 00:26:18 -0700357 synchronized void removeSQLiteClosable(SQLiteClosable closable) {
358 mPrograms.remove(closable);
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700359 }
360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 @Override
362 protected void onAllReferencesReleased() {
363 if (isOpen()) {
Vasu Noriad239ab2010-06-14 16:58:47 -0700364 // close the database which will close all pending statements to be finalized also
365 close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
367 }
368
369 /**
370 * Attempts to release memory that SQLite holds but does not require to
371 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700372 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 * @return the number of bytes actually released
374 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700375 static public native int releaseMemory();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376
377 /**
378 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
379 * around critical sections. This is pretty expensive, so if you know that your
380 * DB will only be used by a single thread then you should set this to false.
381 * The default is true.
382 * @param lockingEnabled set to true to enable locks, false otherwise
383 */
384 public void setLockingEnabled(boolean lockingEnabled) {
385 mLockingEnabled = lockingEnabled;
386 }
387
388 /**
389 * If set then the SQLiteDatabase is made thread-safe by using locks
390 * around critical sections
391 */
392 private boolean mLockingEnabled = true;
393
394 /* package */ void onCorruption() {
Vasu Norif3cf8a42010-03-23 11:41:44 -0700395 EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
Vasu Noriccd95442010-05-28 17:04:16 -0700396 mErrorHandler.onCorruption(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
398
399 /**
400 * Locks the database for exclusive access. The database lock must be held when
401 * touch the native sqlite3* object since it is single threaded and uses
402 * a polling lock contention algorithm. The lock is recursive, and may be acquired
403 * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700404 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 * @see #unlock()
406 */
407 /* package */ void lock() {
Vasu Nori7b04c412010-07-20 10:31:21 -0700408 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 if (!mLockingEnabled) return;
410 mLock.lock();
411 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
412 if (mLock.getHoldCount() == 1) {
413 // Use elapsed real-time since the CPU may sleep when waiting for IO
414 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
415 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
416 }
417 }
418 }
419
420 /**
421 * Locks the database for exclusive access. The database lock must be held when
422 * touch the native sqlite3* object since it is single threaded and uses
423 * a polling lock contention algorithm. The lock is recursive, and may be acquired
424 * multiple times by the same thread.
425 *
426 * @see #unlockForced()
427 */
428 private void lockForced() {
Vasu Nori7b04c412010-07-20 10:31:21 -0700429 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 mLock.lock();
431 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
432 if (mLock.getHoldCount() == 1) {
433 // Use elapsed real-time since the CPU may sleep when waiting for IO
434 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
435 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
436 }
437 }
438 }
439
440 /**
441 * Releases the database lock. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700442 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 * @see #unlock()
444 */
445 /* package */ void unlock() {
446 if (!mLockingEnabled) return;
447 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
448 if (mLock.getHoldCount() == 1) {
449 checkLockHoldTime();
450 }
451 }
452 mLock.unlock();
453 }
454
455 /**
456 * Releases the database lock.
457 *
458 * @see #unlockForced()
459 */
460 private void unlockForced() {
461 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
462 if (mLock.getHoldCount() == 1) {
463 checkLockHoldTime();
464 }
465 }
466 mLock.unlock();
467 }
468
469 private void checkLockHoldTime() {
470 // Use elapsed real-time since the CPU may sleep when waiting for IO
471 long elapsedTime = SystemClock.elapsedRealtime();
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700472 long lockedTime = elapsedTime - mLockAcquiredWallTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
474 !Log.isLoggable(TAG, Log.VERBOSE) &&
475 (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
476 return;
477 }
478 if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
479 int threadTime = (int)
480 ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
481 if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
482 lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
483 mLastLockMessageTime = elapsedTime;
484 String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
485 + threadTime + "ms";
486 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
487 Log.d(TAG, msg, new Exception());
488 } else {
489 Log.d(TAG, msg);
490 }
491 }
492 }
493 }
494
495 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700496 * Begins a transaction in EXCLUSIVE mode.
497 * <p>
498 * Transactions can be nested.
499 * When the outer transaction is ended all of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 * the work done in that transaction and all of the nested transactions will be committed or
501 * rolled back. The changes will be rolled back if any transaction is ended without being
502 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700503 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 * <p>Here is the standard idiom for transactions:
505 *
506 * <pre>
507 * db.beginTransaction();
508 * try {
509 * ...
510 * db.setTransactionSuccessful();
511 * } finally {
512 * db.endTransaction();
513 * }
514 * </pre>
515 */
516 public void beginTransaction() {
Vasu Nori6c354da2010-04-26 23:33:39 -0700517 beginTransaction(null /* transactionStatusCallback */, true);
518 }
519
520 /**
521 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
522 * the outer transaction is ended all of the work done in that transaction
523 * and all of the nested transactions will be committed or rolled back. The
524 * changes will be rolled back if any transaction is ended without being
525 * marked as clean (by calling setTransactionSuccessful). Otherwise they
526 * will be committed.
527 * <p>
528 * Here is the standard idiom for transactions:
529 *
530 * <pre>
531 * db.beginTransactionNonExclusive();
532 * try {
533 * ...
534 * db.setTransactionSuccessful();
535 * } finally {
536 * db.endTransaction();
537 * }
538 * </pre>
539 */
540 public void beginTransactionNonExclusive() {
541 beginTransaction(null /* transactionStatusCallback */, false);
Fred Quintanac4516a72009-09-03 12:14:06 -0700542 }
543
544 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700545 * Begins a transaction in EXCLUSIVE mode.
546 * <p>
547 * Transactions can be nested.
548 * When the outer transaction is ended all of
Fred Quintanac4516a72009-09-03 12:14:06 -0700549 * the work done in that transaction and all of the nested transactions will be committed or
550 * rolled back. The changes will be rolled back if any transaction is ended without being
551 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700552 * </p>
Fred Quintanac4516a72009-09-03 12:14:06 -0700553 * <p>Here is the standard idiom for transactions:
554 *
555 * <pre>
556 * db.beginTransactionWithListener(listener);
557 * try {
558 * ...
559 * db.setTransactionSuccessful();
560 * } finally {
561 * db.endTransaction();
562 * }
563 * </pre>
Vasu Noriccd95442010-05-28 17:04:16 -0700564 *
Fred Quintanac4516a72009-09-03 12:14:06 -0700565 * @param transactionListener listener that should be notified when the transaction begins,
566 * commits, or is rolled back, either explicitly or by a call to
567 * {@link #yieldIfContendedSafely}.
568 */
569 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700570 beginTransaction(transactionListener, true);
571 }
572
573 /**
574 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
575 * the outer transaction is ended all of the work done in that transaction
576 * and all of the nested transactions will be committed or rolled back. The
577 * changes will be rolled back if any transaction is ended without being
578 * marked as clean (by calling setTransactionSuccessful). Otherwise they
579 * will be committed.
580 * <p>
581 * Here is the standard idiom for transactions:
582 *
583 * <pre>
584 * db.beginTransactionWithListenerNonExclusive(listener);
585 * try {
586 * ...
587 * db.setTransactionSuccessful();
588 * } finally {
589 * db.endTransaction();
590 * }
591 * </pre>
592 *
593 * @param transactionListener listener that should be notified when the
594 * transaction begins, commits, or is rolled back, either
595 * explicitly or by a call to {@link #yieldIfContendedSafely}.
596 */
597 public void beginTransactionWithListenerNonExclusive(
598 SQLiteTransactionListener transactionListener) {
599 beginTransaction(transactionListener, false);
600 }
601
602 private void beginTransaction(SQLiteTransactionListener transactionListener,
603 boolean exclusive) {
Vasu Noriccd95442010-05-28 17:04:16 -0700604 verifyDbIsOpen();
Vasu Noric8e1f232010-04-13 15:05:09 -0700605 lockForced();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 boolean ok = false;
607 try {
608 // If this thread already had the lock then get out
609 if (mLock.getHoldCount() > 1) {
610 if (mInnerTransactionIsSuccessful) {
611 String msg = "Cannot call beginTransaction between "
612 + "calling setTransactionSuccessful and endTransaction";
613 IllegalStateException e = new IllegalStateException(msg);
614 Log.e(TAG, "beginTransaction() failed", e);
615 throw e;
616 }
617 ok = true;
618 return;
619 }
620
621 // This thread didn't already have the lock, so begin a database
622 // transaction now.
Vasu Nori57feb5d2010-06-22 10:39:04 -0700623 if (exclusive && mConnectionPool == null) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700624 execSQL("BEGIN EXCLUSIVE;");
625 } else {
626 execSQL("BEGIN IMMEDIATE;");
627 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700628 mTransactionListener = transactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 mTransactionIsSuccessful = true;
630 mInnerTransactionIsSuccessful = false;
Fred Quintanac4516a72009-09-03 12:14:06 -0700631 if (transactionListener != null) {
632 try {
633 transactionListener.onBegin();
634 } catch (RuntimeException e) {
635 execSQL("ROLLBACK;");
636 throw e;
637 }
638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 ok = true;
640 } finally {
641 if (!ok) {
642 // beginTransaction is called before the try block so we must release the lock in
643 // the case of failure.
644 unlockForced();
645 }
646 }
647 }
648
649 /**
650 * End a transaction. See beginTransaction for notes about how to use this and when transactions
651 * are committed and rolled back.
652 */
653 public void endTransaction() {
Vasu Noriccd95442010-05-28 17:04:16 -0700654 verifyLockOwner();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 try {
656 if (mInnerTransactionIsSuccessful) {
657 mInnerTransactionIsSuccessful = false;
658 } else {
659 mTransactionIsSuccessful = false;
660 }
661 if (mLock.getHoldCount() != 1) {
662 return;
663 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700664 RuntimeException savedException = null;
665 if (mTransactionListener != null) {
666 try {
667 if (mTransactionIsSuccessful) {
668 mTransactionListener.onCommit();
669 } else {
670 mTransactionListener.onRollback();
671 }
672 } catch (RuntimeException e) {
673 savedException = e;
674 mTransactionIsSuccessful = false;
675 }
676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 if (mTransactionIsSuccessful) {
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800678 execSQL(COMMIT_SQL);
Vasu Nori6c354da2010-04-26 23:33:39 -0700679 // if write-ahead logging is used, we have to take care of checkpoint.
680 // TODO: should applications be given the flexibility of choosing when to
681 // trigger checkpoint?
682 // for now, do checkpoint after every COMMIT because that is the fastest
683 // way to guarantee that readers will see latest data.
684 // but this is the slowest way to run sqlite with in write-ahead logging mode.
685 if (this.mConnectionPool != null) {
686 execSQL("PRAGMA wal_checkpoint;");
687 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
688 Log.i(TAG, "PRAGMA wal_Checkpoint done");
689 }
690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 } else {
692 try {
693 execSQL("ROLLBACK;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700694 if (savedException != null) {
695 throw savedException;
696 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 } catch (SQLException e) {
698 if (Config.LOGD) {
699 Log.d(TAG, "exception during rollback, maybe the DB previously "
700 + "performed an auto-rollback");
701 }
702 }
703 }
704 } finally {
Fred Quintanac4516a72009-09-03 12:14:06 -0700705 mTransactionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 unlockForced();
707 if (Config.LOGV) {
708 Log.v(TAG, "unlocked " + Thread.currentThread()
709 + ", holdCount is " + mLock.getHoldCount());
710 }
711 }
712 }
713
714 /**
715 * Marks the current transaction as successful. Do not do any more database work between
716 * calling this and calling endTransaction. Do as little non-database work as possible in that
717 * situation too. If any errors are encountered between this and endTransaction the transaction
718 * will still be committed.
719 *
720 * @throws IllegalStateException if the current thread is not in a transaction or the
721 * transaction is already marked as successful.
722 */
723 public void setTransactionSuccessful() {
Vasu Noriccd95442010-05-28 17:04:16 -0700724 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 if (!mLock.isHeldByCurrentThread()) {
726 throw new IllegalStateException("no transaction pending");
727 }
728 if (mInnerTransactionIsSuccessful) {
729 throw new IllegalStateException(
730 "setTransactionSuccessful may only be called once per call to beginTransaction");
731 }
732 mInnerTransactionIsSuccessful = true;
733 }
734
735 /**
736 * return true if there is a transaction pending
737 */
738 public boolean inTransaction() {
Vasu Norice38b982010-07-22 13:57:13 -0700739 return mLock.getHoldCount() > 0 || mTransactionUsingExecSql;
740 }
741
742 /* package */ synchronized void setTransactionUsingExecSqlFlag() {
743 if (Log.isLoggable(TAG, Log.DEBUG)) {
744 Log.i(TAG, "found execSQL('begin transaction')");
745 }
746 mTransactionUsingExecSql = true;
747 }
748
749 /* package */ synchronized void resetTransactionUsingExecSqlFlag() {
750 if (Log.isLoggable(TAG, Log.DEBUG)) {
751 if (mTransactionUsingExecSql) {
752 Log.i(TAG, "found execSQL('commit or end or rollback')");
753 }
754 }
755 mTransactionUsingExecSql = false;
756 }
757
758 /**
759 * Returns true if the caller is considered part of the current transaction, if any.
760 * <p>
761 * Caller is part of the current transaction if either of the following is true
762 * <ol>
763 * <li>If transaction is started by calling beginTransaction() methods AND if the caller is
764 * in the same thread as the thread that started the transaction.
765 * </li>
766 * <li>If the transaction is started by calling {@link #execSQL(String)} like this:
767 * execSQL("BEGIN transaction"). In this case, every thread in the process is considered
768 * part of the current transaction.</li>
769 * </ol>
770 *
771 * @return true if the caller is considered part of the current transaction, if any.
772 */
773 /* package */ synchronized boolean amIInTransaction() {
774 // always do this test on the main database connection - NOT on pooled database connection
775 // since transactions always occur on the main database connections only.
776 SQLiteDatabase db = (isPooledConnection()) ? mParentConnObj : this;
777 boolean b = (!db.inTransaction()) ? false :
778 db.mTransactionUsingExecSql || db.mLock.isHeldByCurrentThread();
779 if (Log.isLoggable(TAG, Log.DEBUG)) {
780 Log.i(TAG, "amIinTransaction: " + b);
781 }
782 return b;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 }
784
785 /**
786 * Checks if the database lock is held by this thread.
787 *
788 * @return true, if this thread is holding the database lock.
789 */
790 public boolean isDbLockedByCurrentThread() {
791 return mLock.isHeldByCurrentThread();
792 }
793
794 /**
795 * Checks if the database is locked by another thread. This is
796 * just an estimate, since this status can change at any time,
797 * including after the call is made but before the result has
798 * been acted upon.
799 *
800 * @return true, if the database is locked by another thread
801 */
802 public boolean isDbLockedByOtherThreads() {
803 return !mLock.isHeldByCurrentThread() && mLock.isLocked();
804 }
805
806 /**
807 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
808 * successful so far. Do not call setTransactionSuccessful before calling this. When this
809 * returns a new transaction will have been created but not marked as successful.
810 * @return true if the transaction was yielded
811 * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
812 * will not be yielded. Use yieldIfContendedSafely instead.
813 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700814 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700816 return yieldIfContendedHelper(false /* do not check yielding */,
817 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 }
819
820 /**
821 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
822 * successful so far. Do not call setTransactionSuccessful before calling this. When this
823 * returns a new transaction will have been created but not marked as successful. This assumes
824 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700825 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 * @return true if the transaction was yielded
827 */
828 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700829 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831
Fred Quintana5c7aede2009-08-27 21:41:27 -0700832 /**
833 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
834 * successful so far. Do not call setTransactionSuccessful before calling this. When this
835 * returns a new transaction will have been created but not marked as successful. This assumes
836 * that there are no nested transactions (beginTransaction has only been called once) and will
837 * throw an exception if that is not the case.
838 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
839 * the lock was actually yielded. This will allow other background threads to make some
840 * more progress than they would if we started the transaction immediately.
841 * @return true if the transaction was yielded
842 */
843 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
844 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
845 }
846
847 private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 if (mLock.getQueueLength() == 0) {
849 // Reset the lock acquire time since we know that the thread was willing to yield
850 // the lock at this time.
851 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
852 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
853 return false;
854 }
855 setTransactionSuccessful();
Fred Quintanac4516a72009-09-03 12:14:06 -0700856 SQLiteTransactionListener transactionListener = mTransactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 endTransaction();
858 if (checkFullyYielded) {
859 if (this.isDbLockedByCurrentThread()) {
860 throw new IllegalStateException(
861 "Db locked more than once. yielfIfContended cannot yield");
862 }
863 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700864 if (sleepAfterYieldDelay > 0) {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700865 // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
866 // check if anyone is using the database. If the database is not contended,
867 // retake the lock and return.
868 long remainingDelay = sleepAfterYieldDelay;
869 while (remainingDelay > 0) {
870 try {
871 Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
872 remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
873 } catch (InterruptedException e) {
874 Thread.interrupted();
875 }
876 remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
877 if (mLock.getQueueLength() == 0) {
878 break;
879 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700880 }
881 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700882 beginTransactionWithListener(transactionListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return true;
884 }
885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 /**
Vasu Nori95675132010-07-21 16:24:40 -0700887 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 */
Vasu Nori95675132010-07-21 16:24:40 -0700889 @Deprecated
890 public Map<String, String> getSyncedTables() {
891 return new HashMap<String, String>(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
893
894 /**
895 * Used to allow returning sub-classes of {@link Cursor} when calling query.
896 */
897 public interface CursorFactory {
898 /**
899 * See
Vasu Noribfe1dc22010-08-25 16:29:02 -0700900 * {@link SQLiteCursor#SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 */
902 public Cursor newCursor(SQLiteDatabase db,
903 SQLiteCursorDriver masterQuery, String editTable,
904 SQLiteQuery query);
905 }
906
907 /**
908 * Open the database according to the flags {@link #OPEN_READWRITE}
909 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
910 *
911 * <p>Sets the locale of the database to the the system's current locale.
912 * Call {@link #setLocale} if you would like something else.</p>
913 *
914 * @param path to database file to open and/or create
915 * @param factory an optional factory class that is called to instantiate a
916 * cursor when query is called, or null for default
917 * @param flags to control database access mode
918 * @return the newly opened database
919 * @throws SQLiteException if the database cannot be opened
920 */
921 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700922 return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
923 }
924
925 /**
Vasu Nori74f170f2010-06-01 18:06:18 -0700926 * Open the database according to the flags {@link #OPEN_READWRITE}
927 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
928 *
929 * <p>Sets the locale of the database to the the system's current locale.
930 * Call {@link #setLocale} if you would like something else.</p>
931 *
932 * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
933 * used to handle corruption when sqlite reports database corruption.</p>
934 *
935 * @param path to database file to open and/or create
936 * @param factory an optional factory class that is called to instantiate a
937 * cursor when query is called, or null for default
938 * @param flags to control database access mode
939 * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
940 * when sqlite reports database corruption
941 * @return the newly opened database
942 * @throws SQLiteException if the database cannot be opened
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700943 */
944 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
945 DatabaseErrorHandler errorHandler) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700946 SQLiteDatabase sqliteDatabase = openDatabase(path, factory, flags, errorHandler,
947 (short) 0 /* the main connection handle */);
Vasu Noria8c24902010-06-01 11:30:27 -0700948
949 // set sqlite pagesize to mBlockSize
950 if (sBlockSize == 0) {
951 // TODO: "/data" should be a static final String constant somewhere. it is hardcoded
952 // in several places right now.
953 sBlockSize = new StatFs("/data").getBlockSize();
954 }
955 sqliteDatabase.setPageSize(sBlockSize);
Vasu Nori57feb5d2010-06-22 10:39:04 -0700956 //STOPSHIP - uncomment the following line
957 //sqliteDatabase.setJournalMode(path, "TRUNCATE");
958 // STOPSHIP remove the following lines
Vasu Nori7b04c412010-07-20 10:31:21 -0700959 if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) {
960 sqliteDatabase.enableWriteAheadLogging();
961 }
962 // END STOPSHIP
Vasu Norif9e2bd02010-06-04 16:49:51 -0700963
Vasu Noriccd95442010-05-28 17:04:16 -0700964 // add this database to the list of databases opened in this process
Vasu Nori0732f792010-07-29 17:24:12 -0700965 synchronized(mActiveDatabases) {
966 mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase));
967 }
Vasu Noric3849202010-03-09 10:47:25 -0800968 return sqliteDatabase;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970
Vasu Nori6c354da2010-04-26 23:33:39 -0700971 private static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
972 DatabaseErrorHandler errorHandler, short connectionNum) {
973 SQLiteDatabase db = new SQLiteDatabase(path, factory, flags, errorHandler, connectionNum);
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700974 try {
Vasu Norice38b982010-07-22 13:57:13 -0700975 if (Log.isLoggable(TAG, Log.DEBUG)) {
976 Log.i(TAG, "opening the db : " + path);
977 }
Vasu Nori6c354da2010-04-26 23:33:39 -0700978 // Open the database.
979 db.dbopen(path, flags);
980 db.setLocale(Locale.getDefault());
981 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
982 db.enableSqlTracing(path, connectionNum);
983 }
984 if (SQLiteDebug.DEBUG_SQL_TIME) {
985 db.enableSqlProfiling(path, connectionNum);
986 }
987 return db;
988 } catch (SQLiteDatabaseCorruptException e) {
989 db.mErrorHandler.onCorruption(db);
990 return SQLiteDatabase.openDatabase(path, factory, flags, errorHandler);
991 } catch (SQLiteException e) {
992 Log.e(TAG, "Failed to open the database. closing it.", e);
993 db.close();
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700994 throw e;
995 }
996 }
997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 /**
999 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
1000 */
1001 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
1002 return openOrCreateDatabase(file.getPath(), factory);
1003 }
1004
1005 /**
1006 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
1007 */
1008 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
1009 return openDatabase(path, factory, CREATE_IF_NECESSARY);
1010 }
1011
1012 /**
Vasu Nori6c354da2010-04-26 23:33:39 -07001013 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
Vasu Nori062fc7ce2010-03-31 16:13:05 -07001014 */
1015 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
1016 DatabaseErrorHandler errorHandler) {
1017 return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
1018 }
1019
Vasu Noria98cb262010-06-22 13:16:35 -07001020 private void setJournalMode(final String dbPath, final String mode) {
1021 // journal mode can be set only for non-memory databases
1022 if (!dbPath.equalsIgnoreCase(MEMORY_DB_PATH)) {
1023 String s = DatabaseUtils.stringForQuery(this, "PRAGMA journal_mode=" + mode, null);
1024 if (!s.equalsIgnoreCase(mode)) {
1025 Log.e(TAG, "setting journal_mode to " + mode + " failed for db: " + dbPath +
1026 " (on pragma set journal_mode, sqlite returned:" + s);
1027 }
1028 }
1029 }
1030
Vasu Nori062fc7ce2010-03-31 16:13:05 -07001031 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 * Create a memory backed SQLite database. Its contents will be destroyed
1033 * when the database is closed.
1034 *
1035 * <p>Sets the locale of the database to the the system's current locale.
1036 * Call {@link #setLocale} if you would like something else.</p>
1037 *
1038 * @param factory an optional factory class that is called to instantiate a
1039 * cursor when query is called
1040 * @return a SQLiteDatabase object, or null if the database can't be created
1041 */
1042 public static SQLiteDatabase create(CursorFactory factory) {
1043 // This is a magic string with special meaning for SQLite.
Vasu Noria98cb262010-06-22 13:16:35 -07001044 return openDatabase(MEMORY_DB_PATH, factory, CREATE_IF_NECESSARY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 }
1046
1047 /**
1048 * Close the database.
1049 */
1050 public void close() {
Vasu Norice38b982010-07-22 13:57:13 -07001051 if (Log.isLoggable(TAG, Log.DEBUG)) {
Vasu Nori75010102010-07-01 16:23:06 -07001052 Log.i(TAG, "closing db: " + mPath + " (connection # " + mConnectionNum);
1053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 lock();
1055 try {
Vasu Noriffe06122010-09-27 12:32:57 -07001056 // some other thread could have closed this database while I was waiting for lock.
1057 // check the database state
1058 if (!isOpen()) {
1059 return;
1060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 closeClosable();
Vasu Norifea6f6d2010-05-21 15:36:06 -07001062 // finalize ALL statements queued up so far
1063 closePendingStatements();
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001064 releaseCustomFunctions();
Vasu Norif6373e92010-03-16 10:21:00 -07001065 // close this database instance - regardless of its reference count value
Vasu Nori422dad02010-09-03 16:03:08 -07001066 closeDatabase();
Vasu Nori6c354da2010-04-26 23:33:39 -07001067 if (mConnectionPool != null) {
Vasu Norice38b982010-07-22 13:57:13 -07001068 if (Log.isLoggable(TAG, Log.DEBUG)) {
1069 assert mConnectionPool != null;
1070 Log.i(TAG, mConnectionPool.toString());
1071 }
Vasu Nori6c354da2010-04-26 23:33:39 -07001072 mConnectionPool.close();
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 } finally {
Vasu Nori422dad02010-09-03 16:03:08 -07001075 unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 }
1077 }
1078
1079 private void closeClosable() {
Vasu Noriccd95442010-05-28 17:04:16 -07001080 /* deallocate all compiled SQL statement objects from mCompiledQueries cache.
Vasu Norie495d1f2010-01-06 16:34:19 -08001081 * this should be done before de-referencing all {@link SQLiteClosable} objects
1082 * from this database object because calling
1083 * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
1084 * to be closed. sqlite doesn't let a database close if there are
1085 * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries.
1086 */
Vasu Norib729dcc2010-09-14 11:35:49 -07001087 deallocCachedSqlStatements();
Vasu Norie495d1f2010-01-06 16:34:19 -08001088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
1090 while (iter.hasNext()) {
1091 Map.Entry<SQLiteClosable, Object> entry = iter.next();
1092 SQLiteClosable program = entry.getKey();
1093 if (program != null) {
1094 program.onAllReferencesReleasedFromContainer();
1095 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001096 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 /**
Vasu Nori422dad02010-09-03 16:03:08 -07001100 * package level access for testing purposes
1101 */
1102 /* package */ void closeDatabase() throws SQLiteException {
1103 try {
1104 dbclose();
1105 } catch (SQLiteUnfinalizedObjectsException e) {
1106 String msg = e.getMessage();
1107 String[] tokens = msg.split(",", 2);
1108 int stmtId = Integer.parseInt(tokens[0]);
1109 // get extra info about this statement, if it is still to be released by closeClosable()
1110 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
1111 boolean found = false;
1112 while (iter.hasNext()) {
1113 Map.Entry<SQLiteClosable, Object> entry = iter.next();
1114 SQLiteClosable program = entry.getKey();
1115 if (program != null && program instanceof SQLiteProgram) {
1116 SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
1117 if (compiledSql.nStatement == stmtId) {
1118 msg = compiledSql.toString();
1119 found = true;
1120 }
1121 }
1122 }
1123 if (!found) {
1124 // the statement is already released by closeClosable(). is it waiting to be
1125 // finalized?
1126 if (mClosedStatementIds.contains(stmtId)) {
1127 Log.w(TAG, "this shouldn't happen. finalizing the statement now: ");
1128 closePendingStatements();
1129 // try to close the database again
1130 closeDatabase();
1131 }
1132 } else {
1133 // the statement is not yet closed. most probably programming error in the app.
1134 Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg);
1135 throw e;
1136 }
1137 }
1138 }
1139
1140 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 * Native call to close the database.
1142 */
1143 private native void dbclose();
1144
1145 /**
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001146 * A callback interface for a custom sqlite3 function.
1147 * This can be used to create a function that can be called from
1148 * sqlite3 database triggers.
1149 * @hide
1150 */
1151 public interface CustomFunction {
1152 public void callback(String[] args);
1153 }
1154
1155 /**
1156 * Registers a CustomFunction callback as a function that can be called from
1157 * sqlite3 database triggers.
1158 * @param name the name of the sqlite3 function
1159 * @param numArgs the number of arguments for the function
1160 * @param function callback to call when the function is executed
1161 * @hide
1162 */
1163 public void addCustomFunction(String name, int numArgs, CustomFunction function) {
1164 verifyDbIsOpen();
1165 synchronized (mCustomFunctions) {
1166 int ref = native_addCustomFunction(name, numArgs, function);
1167 if (ref != 0) {
1168 // save a reference to the function for cleanup later
1169 mCustomFunctions.add(new Integer(ref));
1170 } else {
1171 throw new SQLiteException("failed to add custom function " + name);
1172 }
1173 }
1174 }
1175
1176 private void releaseCustomFunctions() {
1177 synchronized (mCustomFunctions) {
1178 for (int i = 0; i < mCustomFunctions.size(); i++) {
1179 Integer function = mCustomFunctions.get(i);
1180 native_releaseCustomFunction(function.intValue());
1181 }
1182 mCustomFunctions.clear();
1183 }
1184 }
1185
1186 // list of CustomFunction references so we can clean up when the database closes
1187 private final ArrayList<Integer> mCustomFunctions =
1188 new ArrayList<Integer>();
1189
1190 private native int native_addCustomFunction(String name, int numArgs, CustomFunction function);
1191 private native void native_releaseCustomFunction(int function);
1192
1193 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 * Gets the database version.
1195 *
1196 * @return the database version
1197 */
1198 public int getVersion() {
Vasu Noriccd95442010-05-28 17:04:16 -07001199 return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
1201
1202 /**
1203 * Sets the database version.
1204 *
1205 * @param version the new database version
1206 */
1207 public void setVersion(int version) {
1208 execSQL("PRAGMA user_version = " + version);
1209 }
1210
1211 /**
1212 * Returns the maximum size the database may grow to.
1213 *
1214 * @return the new maximum database size
1215 */
1216 public long getMaximumSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001217 long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
1218 return pageCount * getPageSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 }
1220
1221 /**
1222 * Sets the maximum size the database will grow to. The maximum size cannot
1223 * be set below the current size.
1224 *
1225 * @param numBytes the maximum database size, in bytes
1226 * @return the new maximum database size
1227 */
1228 public long setMaximumSize(long numBytes) {
Vasu Noriccd95442010-05-28 17:04:16 -07001229 long pageSize = getPageSize();
1230 long numPages = numBytes / pageSize;
1231 // If numBytes isn't a multiple of pageSize, bump up a page
1232 if ((numBytes % pageSize) != 0) {
1233 numPages++;
Vasu Norif3cf8a42010-03-23 11:41:44 -07001234 }
Vasu Noriccd95442010-05-28 17:04:16 -07001235 long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
1236 null);
1237 return newPageCount * pageSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 }
1239
1240 /**
1241 * Returns the current database page size, in bytes.
1242 *
1243 * @return the database page size, in bytes
1244 */
1245 public long getPageSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001246 return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248
1249 /**
1250 * Sets the database page size. The page size must be a power of two. This
1251 * method does not work if any data has been written to the database file,
1252 * and must be called right after the database has been created.
1253 *
1254 * @param numBytes the database page size, in bytes
1255 */
1256 public void setPageSize(long numBytes) {
1257 execSQL("PRAGMA page_size = " + numBytes);
1258 }
1259
1260 /**
1261 * Mark this table as syncable. When an update occurs in this table the
1262 * _sync_dirty field will be set to ensure proper syncing operation.
1263 *
1264 * @param table the table to mark as syncable
1265 * @param deletedTable The deleted table that corresponds to the
1266 * syncable table
Vasu Nori95675132010-07-21 16:24:40 -07001267 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 */
Vasu Nori95675132010-07-21 16:24:40 -07001269 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 public void markTableSyncable(String table, String deletedTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 }
1272
1273 /**
1274 * Mark this table as syncable, with the _sync_dirty residing in another
1275 * table. When an update occurs in this table the _sync_dirty field of the
1276 * row in updateTable with the _id in foreignKey will be set to
1277 * ensure proper syncing operation.
1278 *
1279 * @param table an update on this table will trigger a sync time removal
1280 * @param foreignKey this is the column in table whose value is an _id in
1281 * updateTable
1282 * @param updateTable this is the table that will have its _sync_dirty
Vasu Nori95675132010-07-21 16:24:40 -07001283 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 */
Vasu Nori95675132010-07-21 16:24:40 -07001285 @Deprecated
1286 public void markTableSyncable(String table, String foreignKey, String updateTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
1288
1289 /**
1290 * Finds the name of the first table, which is editable.
1291 *
1292 * @param tables a list of tables
1293 * @return the first table listed
1294 */
1295 public static String findEditTable(String tables) {
1296 if (!TextUtils.isEmpty(tables)) {
1297 // find the first word terminated by either a space or a comma
1298 int spacepos = tables.indexOf(' ');
1299 int commapos = tables.indexOf(',');
1300
1301 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1302 return tables.substring(0, spacepos);
1303 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1304 return tables.substring(0, commapos);
1305 }
1306 return tables;
1307 } else {
1308 throw new IllegalStateException("Invalid tables");
1309 }
1310 }
1311
1312 /**
1313 * Compiles an SQL statement into a reusable pre-compiled statement object.
1314 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1315 * statement and fill in those values with {@link SQLiteProgram#bindString}
1316 * and {@link SQLiteProgram#bindLong} each time you want to run the
1317 * statement. Statements may not return result sets larger than 1x1.
Vasu Nori2827d6d2010-07-04 00:26:18 -07001318 *<p>
1319 * No two threads should be using the same {@link SQLiteStatement} at the same time.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 *
1321 * @param sql The raw SQL statement, may contain ? for unknown values to be
1322 * bound later.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001323 * @return A pre-compiled {@link SQLiteStatement} object. Note that
1324 * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 */
1326 public SQLiteStatement compileStatement(String sql) throws SQLException {
Vasu Noriccd95442010-05-28 17:04:16 -07001327 verifyDbIsOpen();
Vasu Nori0732f792010-07-29 17:24:12 -07001328 return new SQLiteStatement(this, sql, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 }
1330
1331 /**
1332 * Query the given URL, returning a {@link Cursor} over the result set.
1333 *
1334 * @param distinct true if you want each row to be unique, false otherwise.
1335 * @param table The table name to compile the query against.
1336 * @param columns A list of which columns to return. Passing null will
1337 * return all columns, which is discouraged to prevent reading
1338 * data from storage that isn't going to be used.
1339 * @param selection A filter declaring which rows to return, formatted as an
1340 * SQL WHERE clause (excluding the WHERE itself). Passing null
1341 * will return all rows for the given table.
1342 * @param selectionArgs You may include ?s in selection, which will be
1343 * replaced by the values from selectionArgs, in order that they
1344 * appear in the selection. The values will be bound as Strings.
1345 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1346 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1347 * will cause the rows to not be grouped.
1348 * @param having A filter declare which row groups to include in the cursor,
1349 * if row grouping is being used, formatted as an SQL HAVING
1350 * clause (excluding the HAVING itself). Passing null will cause
1351 * all row groups to be included, and is required when row
1352 * grouping is not being used.
1353 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1354 * (excluding the ORDER BY itself). Passing null will use the
1355 * default sort order, which may be unordered.
1356 * @param limit Limits the number of rows returned by the query,
1357 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001358 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1359 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 * @see Cursor
1361 */
1362 public Cursor query(boolean distinct, String table, String[] columns,
1363 String selection, String[] selectionArgs, String groupBy,
1364 String having, String orderBy, String limit) {
1365 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1366 groupBy, having, orderBy, limit);
1367 }
1368
1369 /**
1370 * Query the given URL, returning a {@link Cursor} over the result set.
1371 *
1372 * @param cursorFactory the cursor factory to use, or null for the default factory
1373 * @param distinct true if you want each row to be unique, false otherwise.
1374 * @param table The table name to compile the query against.
1375 * @param columns A list of which columns to return. Passing null will
1376 * return all columns, which is discouraged to prevent reading
1377 * data from storage that isn't going to be used.
1378 * @param selection A filter declaring which rows to return, formatted as an
1379 * SQL WHERE clause (excluding the WHERE itself). Passing null
1380 * will return all rows for the given table.
1381 * @param selectionArgs You may include ?s in selection, which will be
1382 * replaced by the values from selectionArgs, in order that they
1383 * appear in the selection. The values will be bound as Strings.
1384 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1385 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1386 * will cause the rows to not be grouped.
1387 * @param having A filter declare which row groups to include in the cursor,
1388 * if row grouping is being used, formatted as an SQL HAVING
1389 * clause (excluding the HAVING itself). Passing null will cause
1390 * all row groups to be included, and is required when row
1391 * grouping is not being used.
1392 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1393 * (excluding the ORDER BY itself). Passing null will use the
1394 * default sort order, which may be unordered.
1395 * @param limit Limits the number of rows returned by the query,
1396 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001397 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1398 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 * @see Cursor
1400 */
1401 public Cursor queryWithFactory(CursorFactory cursorFactory,
1402 boolean distinct, String table, String[] columns,
1403 String selection, String[] selectionArgs, String groupBy,
1404 String having, String orderBy, String limit) {
Vasu Noriccd95442010-05-28 17:04:16 -07001405 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 String sql = SQLiteQueryBuilder.buildQueryString(
1407 distinct, table, columns, selection, groupBy, having, orderBy, limit);
1408
1409 return rawQueryWithFactory(
1410 cursorFactory, sql, selectionArgs, findEditTable(table));
1411 }
1412
1413 /**
1414 * Query the given table, returning a {@link Cursor} over the result set.
1415 *
1416 * @param table The table name to compile the query against.
1417 * @param columns A list of which columns to return. Passing null will
1418 * return all columns, which is discouraged to prevent reading
1419 * data from storage that isn't going to be used.
1420 * @param selection A filter declaring which rows to return, formatted as an
1421 * SQL WHERE clause (excluding the WHERE itself). Passing null
1422 * will return all rows for the given table.
1423 * @param selectionArgs You may include ?s in selection, which will be
1424 * replaced by the values from selectionArgs, in order that they
1425 * appear in the selection. The values will be bound as Strings.
1426 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1427 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1428 * will cause the rows to not be grouped.
1429 * @param having A filter declare which row groups to include in the cursor,
1430 * if row grouping is being used, formatted as an SQL HAVING
1431 * clause (excluding the HAVING itself). Passing null will cause
1432 * all row groups to be included, and is required when row
1433 * grouping is not being used.
1434 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1435 * (excluding the ORDER BY itself). Passing null will use the
1436 * default sort order, which may be unordered.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001437 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1438 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 * @see Cursor
1440 */
1441 public Cursor query(String table, String[] columns, String selection,
1442 String[] selectionArgs, String groupBy, String having,
1443 String orderBy) {
1444
1445 return query(false, table, columns, selection, selectionArgs, groupBy,
1446 having, orderBy, null /* limit */);
1447 }
1448
1449 /**
1450 * Query the given table, returning a {@link Cursor} over the result set.
1451 *
1452 * @param table The table name to compile the query against.
1453 * @param columns A list of which columns to return. Passing null will
1454 * return all columns, which is discouraged to prevent reading
1455 * data from storage that isn't going to be used.
1456 * @param selection A filter declaring which rows to return, formatted as an
1457 * SQL WHERE clause (excluding the WHERE itself). Passing null
1458 * will return all rows for the given table.
1459 * @param selectionArgs You may include ?s in selection, which will be
1460 * replaced by the values from selectionArgs, in order that they
1461 * appear in the selection. The values will be bound as Strings.
1462 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1463 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1464 * will cause the rows to not be grouped.
1465 * @param having A filter declare which row groups to include in the cursor,
1466 * if row grouping is being used, formatted as an SQL HAVING
1467 * clause (excluding the HAVING itself). Passing null will cause
1468 * all row groups to be included, and is required when row
1469 * grouping is not being used.
1470 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1471 * (excluding the ORDER BY itself). Passing null will use the
1472 * default sort order, which may be unordered.
1473 * @param limit Limits the number of rows returned by the query,
1474 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001475 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1476 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 * @see Cursor
1478 */
1479 public Cursor query(String table, String[] columns, String selection,
1480 String[] selectionArgs, String groupBy, String having,
1481 String orderBy, String limit) {
1482
1483 return query(false, table, columns, selection, selectionArgs, groupBy,
1484 having, orderBy, limit);
1485 }
1486
1487 /**
1488 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1489 *
1490 * @param sql the SQL query. The SQL string must not be ; terminated
1491 * @param selectionArgs You may include ?s in where clause in the query,
1492 * which will be replaced by the values from selectionArgs. The
1493 * values will be bound as Strings.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001494 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1495 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 */
1497 public Cursor rawQuery(String sql, String[] selectionArgs) {
1498 return rawQueryWithFactory(null, sql, selectionArgs, null);
1499 }
1500
1501 /**
1502 * Runs the provided SQL and returns a cursor over the result set.
1503 *
1504 * @param cursorFactory the cursor factory to use, or null for the default factory
1505 * @param sql the SQL query. The SQL string must not be ; terminated
1506 * @param selectionArgs You may include ?s in where clause in the query,
1507 * which will be replaced by the values from selectionArgs. The
1508 * values will be bound as Strings.
1509 * @param editTable the name of the first table, which is editable
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001510 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1511 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 */
1513 public Cursor rawQueryWithFactory(
1514 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1515 String editTable) {
Vasu Noriccd95442010-05-28 17:04:16 -07001516 verifyDbIsOpen();
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001517 BlockGuard.getThreadPolicy().onReadFromDisk();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 long timeStart = 0;
1519
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001520 if (Config.LOGV || mSlowQueryThreshold != -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 timeStart = System.currentTimeMillis();
1522 }
1523
Vasu Nori6c354da2010-04-26 23:33:39 -07001524 SQLiteDatabase db = getDbConnection(sql);
1525 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(db, sql, editTable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001527 Cursor cursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 try {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001529 cursor = driver.query(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 cursorFactory != null ? cursorFactory : mFactory,
1531 selectionArgs);
1532 } finally {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001533 if (Config.LOGV || mSlowQueryThreshold != -1) {
1534
Vasu Nori020e5342010-04-28 14:22:38 -07001535 // Force query execution
1536 int count = -1;
1537 if (cursor != null) {
1538 count = cursor.getCount();
1539 }
1540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 long duration = System.currentTimeMillis() - timeStart;
1542
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001543 if (Config.LOGV || duration >= mSlowQueryThreshold) {
1544 Log.v(SQLiteCursor.TAG,
1545 "query (" + duration + " ms): " + driver.toString() + ", args are "
1546 + (selectionArgs != null
1547 ? TextUtils.join(",", selectionArgs)
Vasu Nori020e5342010-04-28 14:22:38 -07001548 : "<null>") + ", count is " + count);
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
Vasu Nori6c354da2010-04-26 23:33:39 -07001551 releaseDbConnection(db);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 }
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001553 return cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555
1556 /**
1557 * Runs the provided SQL and returns a cursor over the result set.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001558 * The cursor will read an initial set of rows and the return to the caller.
1559 * It will continue to read in batches and send data changed notifications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 * when the later batches are ready.
1561 * @param sql the SQL query. The SQL string must not be ; terminated
1562 * @param selectionArgs You may include ?s in where clause in the query,
1563 * which will be replaced by the values from selectionArgs. The
1564 * values will be bound as Strings.
1565 * @param initialRead set the initial count of items to read from the cursor
1566 * @param maxRead set the count of items to read on each iteration after the first
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001567 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1568 * {@link Cursor}s are not synchronized, see the documentation for more details.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001569 *
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001570 * This work is incomplete and not fully tested or reviewed, so currently
1571 * hidden.
1572 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001574 public Cursor rawQuery(String sql, String[] selectionArgs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 int initialRead, int maxRead) {
1576 SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1577 null, sql, selectionArgs, null);
1578 c.setLoadStyle(initialRead, maxRead);
1579 return c;
1580 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 /**
1583 * Convenience method for inserting a row into the database.
1584 *
1585 * @param table the table to insert the row into
1586 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1587 * so if initialValues is empty this column will explicitly be
1588 * assigned a NULL value
1589 * @param values this map contains the initial column values for the
1590 * row. The keys should be the column names and the values the
1591 * column values
1592 * @return the row ID of the newly inserted row, or -1 if an error occurred
1593 */
1594 public long insert(String table, String nullColumnHack, ContentValues values) {
1595 try {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001596 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 } catch (SQLException e) {
1598 Log.e(TAG, "Error inserting " + values, e);
1599 return -1;
1600 }
1601 }
1602
1603 /**
1604 * Convenience method for inserting a row into the database.
1605 *
1606 * @param table the table to insert the row into
1607 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1608 * so if initialValues is empty this column will explicitly be
1609 * assigned a NULL value
1610 * @param values this map contains the initial column values for the
1611 * row. The keys should be the column names and the values the
1612 * column values
1613 * @throws SQLException
1614 * @return the row ID of the newly inserted row, or -1 if an error occurred
1615 */
1616 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1617 throws SQLException {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001618 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 }
1620
1621 /**
1622 * Convenience method for replacing a row in the database.
1623 *
1624 * @param table the table in which to replace the row
1625 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1626 * so if initialValues is empty this row will explicitly be
1627 * assigned a NULL value
1628 * @param initialValues this map contains the initial column values for
1629 * the row. The key
1630 * @return the row ID of the newly inserted row, or -1 if an error occurred
1631 */
1632 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1633 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001634 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001635 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 } catch (SQLException e) {
1637 Log.e(TAG, "Error inserting " + initialValues, e);
1638 return -1;
1639 }
1640 }
1641
1642 /**
1643 * Convenience method for replacing a row in the database.
1644 *
1645 * @param table the table in which to replace the row
1646 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1647 * so if initialValues is empty this row will explicitly be
1648 * assigned a NULL value
1649 * @param initialValues this map contains the initial column values for
1650 * the row. The key
1651 * @throws SQLException
1652 * @return the row ID of the newly inserted row, or -1 if an error occurred
1653 */
1654 public long replaceOrThrow(String table, String nullColumnHack,
1655 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001656 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001657 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 }
1659
1660 /**
1661 * General method for inserting a row into the database.
1662 *
1663 * @param table the table to insert the row into
1664 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1665 * so if initialValues is empty this column will explicitly be
1666 * assigned a NULL value
1667 * @param initialValues this map contains the initial column values for the
1668 * row. The keys should be the column names and the values the
1669 * column values
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001670 * @param conflictAlgorithm for insert conflict resolver
Vasu Nori6eb7c452010-01-27 14:31:24 -08001671 * @return the row ID of the newly inserted row
1672 * OR the primary key of the existing row if the input param 'conflictAlgorithm' =
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001673 * {@link #CONFLICT_IGNORE}
Vasu Nori6eb7c452010-01-27 14:31:24 -08001674 * OR -1 if any error
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 */
1676 public long insertWithOnConflict(String table, String nullColumnHack,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001677 ContentValues initialValues, int conflictAlgorithm) {
Vasu Nori0732f792010-07-29 17:24:12 -07001678 StringBuilder sql = new StringBuilder();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 sql.append("INSERT");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001680 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 sql.append(" INTO ");
1682 sql.append(table);
Vasu Nori0732f792010-07-29 17:24:12 -07001683 sql.append('(');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684
Vasu Nori0732f792010-07-29 17:24:12 -07001685 Object[] bindArgs = null;
1686 int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0;
1687 if (size > 0) {
1688 bindArgs = new Object[size];
1689 int i = 0;
1690 for (String colName : initialValues.keySet()) {
1691 sql.append((i > 0) ? "," : "");
1692 sql.append(colName);
1693 bindArgs[i++] = initialValues.get(colName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 sql.append(')');
Vasu Nori0732f792010-07-29 17:24:12 -07001696 sql.append(" VALUES (");
1697 for (i = 0; i < size; i++) {
1698 sql.append((i > 0) ? ",?" : "?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Vasu Nori0732f792010-07-29 17:24:12 -07001700 } else {
1701 sql.append(nullColumnHack + ") VALUES (NULL");
1702 }
1703 sql.append(')');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704
Vasu Nori0732f792010-07-29 17:24:12 -07001705 SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
1706 try {
Vasu Norifb16cbd2010-07-25 16:38:48 -07001707 return statement.executeInsert();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 } catch (SQLiteDatabaseCorruptException e) {
1709 onCorruption();
1710 throw e;
1711 } finally {
Vasu Nori0732f792010-07-29 17:24:12 -07001712 statement.close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714 }
1715
1716 /**
1717 * Convenience method for deleting rows in the database.
1718 *
1719 * @param table the table to delete from
1720 * @param whereClause the optional WHERE clause to apply when deleting.
1721 * Passing null will delete all rows.
1722 * @return the number of rows affected if a whereClause is passed in, 0
1723 * otherwise. To remove all rows and get a count pass "1" as the
1724 * whereClause.
1725 */
1726 public int delete(String table, String whereClause, String[] whereArgs) {
Vasu Nori0732f792010-07-29 17:24:12 -07001727 SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
1728 (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 try {
Vasu Norifb16cbd2010-07-25 16:38:48 -07001730 return statement.executeUpdateDelete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 } catch (SQLiteDatabaseCorruptException e) {
1732 onCorruption();
1733 throw e;
1734 } finally {
Vasu Nori0732f792010-07-29 17:24:12 -07001735 statement.close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 }
1737 }
1738
1739 /**
1740 * Convenience method for updating rows in the database.
1741 *
1742 * @param table the table to update in
1743 * @param values a map from column names to new column values. null is a
1744 * valid value that will be translated to NULL.
1745 * @param whereClause the optional WHERE clause to apply when updating.
1746 * Passing null will update all rows.
1747 * @return the number of rows affected
1748 */
1749 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001750 return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 /**
1754 * Convenience method for updating rows in the database.
1755 *
1756 * @param table the table to update in
1757 * @param values a map from column names to new column values. null is a
1758 * valid value that will be translated to NULL.
1759 * @param whereClause the optional WHERE clause to apply when updating.
1760 * Passing null will update all rows.
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001761 * @param conflictAlgorithm for update conflict resolver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 * @return the number of rows affected
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001764 public int updateWithOnConflict(String table, ContentValues values,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001765 String whereClause, String[] whereArgs, int conflictAlgorithm) {
Vasu Nori0732f792010-07-29 17:24:12 -07001766 int setValuesSize = values.size();
1767 if (values == null || setValuesSize == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 throw new IllegalArgumentException("Empty values");
1769 }
1770
1771 StringBuilder sql = new StringBuilder(120);
1772 sql.append("UPDATE ");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001773 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 sql.append(table);
1775 sql.append(" SET ");
1776
Vasu Nori0732f792010-07-29 17:24:12 -07001777 // move all bind args to one array
1778 int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
1779 Object[] bindArgs = new Object[bindArgsSize];
1780 int i = 0;
1781 for (String colName : values.keySet()) {
1782 sql.append((i > 0) ? "," : "");
1783 sql.append(colName);
1784 bindArgs[i++] = values.get(colName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 sql.append("=?");
Vasu Nori0732f792010-07-29 17:24:12 -07001786 }
1787 if (whereArgs != null) {
1788 for (i = setValuesSize; i < bindArgsSize; i++) {
1789 bindArgs[i] = whereArgs[i - setValuesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
1791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 if (!TextUtils.isEmpty(whereClause)) {
1793 sql.append(" WHERE ");
1794 sql.append(whereClause);
1795 }
1796
Vasu Nori0732f792010-07-29 17:24:12 -07001797 SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 try {
Vasu Norifb16cbd2010-07-25 16:38:48 -07001799 return statement.executeUpdateDelete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 } catch (SQLiteDatabaseCorruptException e) {
1801 onCorruption();
1802 throw e;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 } finally {
Vasu Nori0732f792010-07-29 17:24:12 -07001804 statement.close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 }
1806 }
1807
1808 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001809 * Execute a single SQL statement that is NOT a SELECT
1810 * or any other SQL statement that returns data.
1811 * <p>
Vasu Norice38b982010-07-22 13:57:13 -07001812 * It has no means to return any data (such as the number of affected rows).
Vasu Noriccd95442010-05-28 17:04:16 -07001813 * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
1814 * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
1815 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001816 * <p>
1817 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1818 * automatically managed by this class. So, do not set journal_mode
1819 * using "PRAGMA journal_mode'<value>" statement if your app is using
1820 * {@link #enableWriteAheadLogging()}
1821 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 *
Vasu Noriccd95442010-05-28 17:04:16 -07001823 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1824 * not supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 * @throws SQLException If the SQL string is invalid for some reason
1826 */
Vasu Norib83cb7c2010-09-14 13:36:01 -07001827 public void execSQL(String sql) throws SQLException {
Vasu Norice38b982010-07-22 13:57:13 -07001828 int stmtType = DatabaseUtils.getSqlStatementType(sql);
1829 if (stmtType == DatabaseUtils.STATEMENT_ATTACH) {
Vasu Nori8d111032010-06-22 18:34:21 -07001830 disableWriteAheadLogging();
1831 }
Vasu Noric8e1f232010-04-13 15:05:09 -07001832 long timeStart = SystemClock.uptimeMillis();
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001833 logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
Vasu Norib83cb7c2010-09-14 13:36:01 -07001834 executeSql(sql, null);
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001835
1836 // Log commit statements along with the most recently executed
Vasu Norice38b982010-07-22 13:57:13 -07001837 // SQL statement for disambiguation.
1838 if (stmtType == DatabaseUtils.STATEMENT_COMMIT) {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001839 logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL);
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001840 } else {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001841 logTimeStat(sql, timeStart, null);
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 }
1844
1845 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001846 * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
1847 * <p>
1848 * For INSERT statements, use any of the following instead.
1849 * <ul>
1850 * <li>{@link #insert(String, String, ContentValues)}</li>
1851 * <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
1852 * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
1853 * </ul>
1854 * <p>
1855 * For UPDATE statements, use any of the following instead.
1856 * <ul>
1857 * <li>{@link #update(String, ContentValues, String, String[])}</li>
1858 * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
1859 * </ul>
1860 * <p>
1861 * For DELETE statements, use any of the following instead.
1862 * <ul>
1863 * <li>{@link #delete(String, String, String[])}</li>
1864 * </ul>
1865 * <p>
1866 * For example, the following are good candidates for using this method:
1867 * <ul>
1868 * <li>ALTER TABLE</li>
1869 * <li>CREATE or DROP table / trigger / view / index / virtual table</li>
1870 * <li>REINDEX</li>
1871 * <li>RELEASE</li>
1872 * <li>SAVEPOINT</li>
1873 * <li>PRAGMA that returns no data</li>
1874 * </ul>
1875 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001876 * <p>
1877 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1878 * automatically managed by this class. So, do not set journal_mode
1879 * using "PRAGMA journal_mode'<value>" statement if your app is using
1880 * {@link #enableWriteAheadLogging()}
1881 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 *
Vasu Noriccd95442010-05-28 17:04:16 -07001883 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1884 * not supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1886 * @throws SQLException If the SQL string is invalid for some reason
1887 */
Vasu Norib83cb7c2010-09-14 13:36:01 -07001888 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 if (bindArgs == null) {
1890 throw new IllegalArgumentException("Empty bindArgs");
1891 }
Vasu Norib83cb7c2010-09-14 13:36:01 -07001892 executeSql(sql, bindArgs);
Vasu Norice38b982010-07-22 13:57:13 -07001893 }
1894
Vasu Nori54025902010-09-14 12:14:26 -07001895 private int executeSql(String sql, Object[] bindArgs) throws SQLException {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001896 long timeStart = SystemClock.uptimeMillis();
Vasu Nori54025902010-09-14 12:14:26 -07001897 int n;
Vasu Nori0732f792010-07-29 17:24:12 -07001898 SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 try {
Vasu Nori54025902010-09-14 12:14:26 -07001900 n = statement.executeUpdateDelete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 } catch (SQLiteDatabaseCorruptException e) {
1902 onCorruption();
1903 throw e;
1904 } finally {
Vasu Nori0732f792010-07-29 17:24:12 -07001905 statement.close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
Dan Egnor12311952009-11-23 14:47:45 -08001907 logTimeStat(sql, timeStart);
Vasu Nori54025902010-09-14 12:14:26 -07001908 return n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 }
1910
1911 @Override
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001912 protected void finalize() throws Throwable {
1913 try {
1914 if (isOpen()) {
1915 Log.e(TAG, "close() was never explicitly called on database '" +
1916 mPath + "' ", mStackTrace);
1917 closeClosable();
1918 onAllReferencesReleased();
1919 releaseCustomFunctions();
1920 }
1921 } finally {
1922 super.finalize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 }
1924 }
1925
1926 /**
Vasu Nori21343692010-06-03 16:01:39 -07001927 * Private constructor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 *
1929 * @param path The full path to the database
1930 * @param factory The factory to use when creating cursors, may be NULL.
1931 * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
1932 * exists, mFlags will be updated appropriately.
Vasu Nori21343692010-06-03 16:01:39 -07001933 * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite reports database
1934 * corruption. may be NULL.
Vasu Nori6c354da2010-04-26 23:33:39 -07001935 * @param connectionNum 0 for main database connection handle. 1..N for pooled database
1936 * connection handles.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 */
Vasu Nori21343692010-06-03 16:01:39 -07001938 private SQLiteDatabase(String path, CursorFactory factory, int flags,
Vasu Nori6c354da2010-04-26 23:33:39 -07001939 DatabaseErrorHandler errorHandler, short connectionNum) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 if (path == null) {
1941 throw new IllegalArgumentException("path should not be null");
1942 }
1943 mFlags = flags;
1944 mPath = path;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001945 mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
Vasu Nori08b448e2010-03-03 10:05:16 -08001946 mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 mFactory = factory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 mPrograms = new WeakHashMap<SQLiteClosable,Object>();
Vasu Nori21343692010-06-03 16:01:39 -07001949 // Set the DatabaseErrorHandler to be used when SQLite reports corruption.
1950 // If the caller sets errorHandler = null, then use default errorhandler.
1951 mErrorHandler = (errorHandler == null) ? new DefaultDatabaseErrorHandler() : errorHandler;
Vasu Nori6c354da2010-04-26 23:33:39 -07001952 mConnectionNum = connectionNum;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 }
1954
1955 /**
1956 * return whether the DB is opened as read only.
1957 * @return true if DB is opened as read only
1958 */
1959 public boolean isReadOnly() {
1960 return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1961 }
1962
1963 /**
1964 * @return true if the DB is currently open (has not been closed)
1965 */
1966 public boolean isOpen() {
1967 return mNativeHandle != 0;
1968 }
1969
1970 public boolean needUpgrade(int newVersion) {
1971 return newVersion > getVersion();
1972 }
1973
1974 /**
1975 * Getter for the path to the database file.
1976 *
1977 * @return the path to our database file.
1978 */
1979 public final String getPath() {
1980 return mPath;
1981 }
1982
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001983 /* package */ void logTimeStat(String sql, long beginMillis) {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001984 logTimeStat(sql, beginMillis, null);
1985 }
1986
1987 /* package */ void logTimeStat(String sql, long beginMillis, String prefix) {
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001988 // Keep track of the last statement executed here, as this is
1989 // the common funnel through which all methods of hitting
1990 // libsqlite eventually flow.
1991 mLastSqlStatement = sql;
1992
Dan Egnor12311952009-11-23 14:47:45 -08001993 // Sample fast queries in proportion to the time taken.
1994 // Quantize the % first, so the logged sampling probability
1995 // exactly equals the actual sampling rate for this query.
1996
1997 int samplePercent;
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001998 long durationMillis = SystemClock.uptimeMillis() - beginMillis;
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001999 if (durationMillis == 0 && prefix == GET_LOCK_LOG_PREFIX) {
2000 // The common case is locks being uncontended. Don't log those,
2001 // even at 1%, which is our default below.
2002 return;
2003 }
2004 if (sQueryLogTimeInMillis == 0) {
2005 sQueryLogTimeInMillis = SystemProperties.getInt("db.db_operation.threshold_ms", 500);
2006 }
2007 if (durationMillis >= sQueryLogTimeInMillis) {
Dan Egnor12311952009-11-23 14:47:45 -08002008 samplePercent = 100;
Vasu Norifb16cbd2010-07-25 16:38:48 -07002009 } else {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002010 samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1;
Dan Egnor799f7212009-11-24 16:24:44 -08002011 if (mRandom.nextInt(100) >= samplePercent) return;
Dan Egnor12311952009-11-23 14:47:45 -08002012 }
2013
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002014 // Note: the prefix will be "COMMIT;" or "GETLOCK:" when non-null. We wait to do
2015 // it here so we avoid allocating in the common case.
2016 if (prefix != null) {
2017 sql = prefix + sql;
2018 }
2019
Dan Egnor12311952009-11-23 14:47:45 -08002020 if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
2021
2022 // ActivityThread.currentPackageName() only returns non-null if the
2023 // current thread is an application main thread. This parameter tells
2024 // us whether an event loop is blocked, and if so, which app it is.
2025 //
2026 // Sadly, there's no fast way to determine app name if this is *not* a
2027 // main thread, or when we are invoked via Binder (e.g. ContentProvider).
2028 // Hopefully the full path to the database will be informative enough.
2029
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002030 String blockingPackage = AppGlobals.getInitialPackage();
Dan Egnor12311952009-11-23 14:47:45 -08002031 if (blockingPackage == null) blockingPackage = "";
2032
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08002033 EventLog.writeEvent(
Brad Fitzpatrickd8330232010-02-19 10:59:01 -08002034 EVENT_DB_OPERATION,
2035 getPathForLogs(),
2036 sql,
2037 durationMillis,
2038 blockingPackage,
2039 samplePercent);
2040 }
2041
2042 /**
2043 * Removes email addresses from database filenames before they're
2044 * logged to the EventLog where otherwise apps could potentially
2045 * read them.
2046 */
2047 private String getPathForLogs() {
2048 if (mPathForLogs != null) {
2049 return mPathForLogs;
2050 }
2051 if (mPath == null) {
2052 return null;
2053 }
2054 if (mPath.indexOf('@') == -1) {
2055 mPathForLogs = mPath;
2056 } else {
2057 mPathForLogs = EMAIL_IN_DB_PATTERN.matcher(mPath).replaceAll("XX@YY");
2058 }
2059 return mPathForLogs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 }
2061
2062 /**
2063 * Sets the locale for this database. Does nothing if this database has
2064 * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
2065 * @throws SQLException if the locale could not be set. The most common reason
2066 * for this is that there is no collator available for the locale you requested.
2067 * In this case the database remains unchanged.
2068 */
2069 public void setLocale(Locale locale) {
2070 lock();
2071 try {
2072 native_setLocale(locale.toString(), mFlags);
2073 } finally {
2074 unlock();
2075 }
2076 }
2077
Vasu Noriccd95442010-05-28 17:04:16 -07002078 /* package */ void verifyDbIsOpen() {
Vasu Nori9463f292010-04-30 12:22:18 -07002079 if (!isOpen()) {
Vasu Nori75010102010-07-01 16:23:06 -07002080 throw new IllegalStateException("database " + getPath() + " (conn# " +
2081 mConnectionNum + ") already closed");
Vasu Nori9463f292010-04-30 12:22:18 -07002082 }
Vasu Noriccd95442010-05-28 17:04:16 -07002083 }
2084
2085 /* package */ void verifyLockOwner() {
2086 verifyDbIsOpen();
2087 if (mLockingEnabled && !isDbLockedByCurrentThread()) {
Vasu Nori9463f292010-04-30 12:22:18 -07002088 throw new IllegalStateException("Don't have database lock!");
2089 }
2090 }
2091
Vasu Norib729dcc2010-09-14 11:35:49 -07002092 /**
2093 * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the
2094 * cache of compiledQueries attached to 'this'.
2095 * <p>
2096 * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL,
2097 * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
2098 * mapping is NOT replaced with the new mapping).
2099 */
2100 /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
2101 synchronized(mCompiledQueries) {
2102 // don't insert the new mapping if a mapping already exists
2103 if (mCompiledQueries.containsKey(sql)) {
2104 return;
2105 }
2106
Vasu Noriffe06122010-09-27 12:32:57 -07002107 if (!mCacheFullWarning && mCompiledQueries.size() == mMaxSqlCacheSize) {
Vasu Norib729dcc2010-09-14 11:35:49 -07002108 /*
2109 * cache size of {@link #mMaxSqlCacheSize} is not enough for this app.
2110 * log a warning.
2111 * chances are it is NOT using ? for bindargs - or cachesize is too small.
2112 */
Vasu Nori5e89ae22010-09-15 14:23:29 -07002113 Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
2114 getPath() + ". Use setMaxSqlCacheSize() to increase cachesize. ");
Vasu Noriffe06122010-09-27 12:32:57 -07002115 mCacheFullWarning = true;
Vasu Norib729dcc2010-09-14 11:35:49 -07002116 }
2117 /* add the given SQLiteCompiledSql compiledStatement to cache.
2118 * no need to worry about the cache size - because {@link #mCompiledQueries}
2119 * self-limits its size to {@link #mMaxSqlCacheSize}.
2120 */
2121 mCompiledQueries.put(sql, compiledStatement);
Vasu Norib729dcc2010-09-14 11:35:49 -07002122 }
2123 }
2124
2125 /** package-level access for testing purposes */
2126 /* package */ void deallocCachedSqlStatements() {
2127 synchronized (mCompiledQueries) {
2128 for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
2129 compiledSql.releaseSqlStatement();
2130 }
2131 mCompiledQueries.clear();
2132 }
2133 }
2134
2135 /**
2136 * From the compiledQueries cache, returns the compiled-statement-id for the given SQL.
2137 * Returns null, if not found in the cache.
2138 */
Vasu Noriffe06122010-09-27 12:32:57 -07002139 /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
2140 synchronized (mCompiledQueries) {
2141 SQLiteCompiledSql compiledStatement = mCompiledQueries.get(sql);
2142 if (compiledStatement == null) {
2143 mNumCacheMisses++;
2144 return null;
2145 }
2146 mNumCacheHits++;
2147 return compiledStatement;
Vasu Norib729dcc2010-09-14 11:35:49 -07002148 }
Vasu Norib729dcc2010-09-14 11:35:49 -07002149 }
2150
Vasu Norie495d1f2010-01-06 16:34:19 -08002151 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002152 * Sets the maximum size of the prepared-statement cache for this database.
Vasu Norie495d1f2010-01-06 16:34:19 -08002153 * (size of the cache = number of compiled-sql-statements stored in the cache).
Vasu Noriccd95442010-05-28 17:04:16 -07002154 *<p>
Vasu Norib729dcc2010-09-14 11:35:49 -07002155 * Maximum cache size can ONLY be increased from its current size (default = 10).
Vasu Noriccd95442010-05-28 17:04:16 -07002156 * If this method is called with smaller size than the current maximum value,
2157 * then IllegalStateException is thrown.
Vasu Norib729dcc2010-09-14 11:35:49 -07002158 *<p>
2159 * This method is thread-safe.
Vasu Norie495d1f2010-01-06 16:34:19 -08002160 *
Vasu Nori90a367262010-04-12 12:49:09 -07002161 * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
2162 * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or
Vasu Noribfe1dc22010-08-25 16:29:02 -07002163 * the value set with previous setMaxSqlCacheSize() call.
Vasu Norie495d1f2010-01-06 16:34:19 -08002164 */
Vasu Nori54025902010-09-14 12:14:26 -07002165 public void setMaxSqlCacheSize(int cacheSize) {
Vasu Noriffe06122010-09-27 12:32:57 -07002166 synchronized(mCompiledQueries) {
Vasu Nori54025902010-09-14 12:14:26 -07002167 if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
2168 throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE);
2169 } else if (cacheSize < mMaxSqlCacheSize) {
2170 throw new IllegalStateException("cannot set cacheSize to a value less than the value " +
2171 "set with previous setMaxSqlCacheSize() call.");
2172 }
2173 mMaxSqlCacheSize = cacheSize;
Vasu Norib729dcc2010-09-14 11:35:49 -07002174 }
Vasu Norib729dcc2010-09-14 11:35:49 -07002175 }
2176
2177 /* package */ boolean isSqlInStatementCache(String sql) {
2178 synchronized (mCompiledQueries) {
2179 return mCompiledQueries.containsKey(sql);
2180 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002181 }
2182
Vasu Nori5e89ae22010-09-15 14:23:29 -07002183 private synchronized int getCacheHitNum() {
2184 return mNumCacheHits;
2185 }
2186
2187 private synchronized int getCacheMissNum() {
2188 return mNumCacheMisses;
2189 }
2190
2191 private synchronized int getCachesize() {
2192 return mCompiledQueries.size();
2193 }
2194
Vasu Nori6f37f832010-05-19 11:53:25 -07002195 /* package */ void finalizeStatementLater(int id) {
2196 if (!isOpen()) {
2197 // database already closed. this statement will already have been finalized.
2198 return;
2199 }
2200 synchronized(mClosedStatementIds) {
2201 if (mClosedStatementIds.contains(id)) {
2202 // this statement id is already queued up for finalization.
2203 return;
2204 }
2205 mClosedStatementIds.add(id);
2206 }
2207 }
2208
Vasu Norice38b982010-07-22 13:57:13 -07002209 /* package */ void closePendingStatements() {
Vasu Nori6f37f832010-05-19 11:53:25 -07002210 if (!isOpen()) {
2211 // since this database is already closed, no need to finalize anything.
2212 mClosedStatementIds.clear();
2213 return;
2214 }
2215 verifyLockOwner();
2216 /* to minimize synchronization on mClosedStatementIds, make a copy of the list */
2217 ArrayList<Integer> list = new ArrayList<Integer>(mClosedStatementIds.size());
2218 synchronized(mClosedStatementIds) {
2219 list.addAll(mClosedStatementIds);
2220 mClosedStatementIds.clear();
2221 }
2222 // finalize all the statements from the copied list
2223 int size = list.size();
2224 for (int i = 0; i < size; i++) {
2225 native_finalize(list.get(i));
2226 }
2227 }
2228
2229 /**
2230 * for testing only
Vasu Nori6f37f832010-05-19 11:53:25 -07002231 */
Vasu Norice38b982010-07-22 13:57:13 -07002232 /* package */ ArrayList<Integer> getQueuedUpStmtList() {
Vasu Nori6f37f832010-05-19 11:53:25 -07002233 return mClosedStatementIds;
2234 }
2235
Vasu Nori6c354da2010-04-26 23:33:39 -07002236 /**
2237 * This method enables parallel execution of queries from multiple threads on the same database.
2238 * It does this by opening multiple handles to the database and using a different
2239 * database handle for each query.
2240 * <p>
2241 * If a transaction is in progress on one connection handle and say, a table is updated in the
2242 * transaction, then query on the same table on another connection handle will block for the
2243 * transaction to complete. But this method enables such queries to execute by having them
2244 * return old version of the data from the table. Most often it is the data that existed in the
2245 * table prior to the above transaction updates on that table.
2246 * <p>
2247 * Maximum number of simultaneous handles used to execute queries in parallel is
2248 * dependent upon the device memory and possibly other properties.
2249 * <p>
2250 * After calling this method, execution of queries in parallel is enabled as long as this
2251 * database handle is open. To disable execution of queries in parallel, database should
2252 * be closed and reopened.
2253 * <p>
2254 * If a query is part of a transaction, then it is executed on the same database handle the
2255 * transaction was begun.
Vasu Nori6c354da2010-04-26 23:33:39 -07002256 * <p>
2257 * If the database has any attached databases, then execution of queries in paralel is NOT
Vasu Noria98cb262010-06-22 13:16:35 -07002258 * possible. In such cases, a message is printed to logcat and false is returned.
2259 * <p>
2260 * This feature is not available for :memory: databases. In such cases,
2261 * a message is printed to logcat and false is returned.
Vasu Nori6c354da2010-04-26 23:33:39 -07002262 * <p>
2263 * A typical way to use this method is the following:
2264 * <pre>
2265 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2266 * CREATE_IF_NECESSARY, myDatabaseErrorHandler);
2267 * db.enableWriteAheadLogging();
2268 * </pre>
2269 * <p>
2270 * Writers should use {@link #beginTransactionNonExclusive()} or
2271 * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
2272 * to start a trsnsaction.
2273 * Non-exclusive mode allows database file to be in readable by threads executing queries.
2274 * </p>
2275 *
Vasu Noria98cb262010-06-22 13:16:35 -07002276 * @return true if write-ahead-logging is set. false otherwise
Vasu Nori6c354da2010-04-26 23:33:39 -07002277 */
Vasu Noriffe06122010-09-27 12:32:57 -07002278 public boolean enableWriteAheadLogging() {
2279 synchronized(this) {
2280 if (mPath.equalsIgnoreCase(MEMORY_DB_PATH)) {
2281 Log.i(TAG, "can't enable WAL for memory databases.");
2282 return false;
Vasu Norice38b982010-07-22 13:57:13 -07002283 }
Vasu Noriffe06122010-09-27 12:32:57 -07002284
2285 // make sure this database has NO attached databases because sqlite's write-ahead-logging
2286 // doesn't work for databases with attached databases
2287 if (getAttachedDbs().size() > 1) {
2288 if (Log.isLoggable(TAG, Log.DEBUG)) {
2289 Log.d(TAG,
2290 "this database: " + mPath + " has attached databases. can't enable WAL.");
2291 }
2292 return false;
2293 }
2294 if (mConnectionPool == null) {
2295 mConnectionPool = new DatabaseConnectionPool(this);
2296 setJournalMode(mPath, "WAL");
2297 }
2298 return true;
Vasu Nori6c354da2010-04-26 23:33:39 -07002299 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002300 }
2301
Vasu Nori2827d6d2010-07-04 00:26:18 -07002302 /**
Vasu Nori7b04c412010-07-20 10:31:21 -07002303 * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
2304 * @hide
Vasu Nori2827d6d2010-07-04 00:26:18 -07002305 */
Vasu Nori7b04c412010-07-20 10:31:21 -07002306 public void disableWriteAheadLogging() {
2307 synchronized (this) {
2308 if (mConnectionPool == null) {
2309 return;
2310 }
2311 mConnectionPool.close();
2312 mConnectionPool = null;
2313 setJournalMode(mPath, "TRUNCATE");
Vasu Nori8d111032010-06-22 18:34:21 -07002314 }
Vasu Nori8d111032010-06-22 18:34:21 -07002315 }
2316
Vasu Nori65a88832010-07-16 15:14:08 -07002317 /* package */ SQLiteDatabase getDatabaseHandle(String sql) {
2318 if (isPooledConnection()) {
2319 // this is a pooled database connection
Vasu Norice38b982010-07-22 13:57:13 -07002320 // use it if it is open AND if I am not currently part of a transaction
2321 if (isOpen() && !amIInTransaction()) {
Vasu Nori65a88832010-07-16 15:14:08 -07002322 // TODO: use another connection from the pool
2323 // if this connection is currently in use by some other thread
2324 // AND if there are free connections in the pool
2325 return this;
2326 } else {
2327 // the pooled connection is not open! could have been closed either due
2328 // to corruption on this or some other connection to the database
2329 // OR, maybe the connection pool is disabled after this connection has been
2330 // allocated to me. try to get some other pooled or main database connection
2331 return getParentDbConnObj().getDbConnection(sql);
2332 }
2333 } else {
2334 // this is NOT a pooled connection. can we get one?
2335 return getDbConnection(sql);
2336 }
2337 }
2338
Vasu Nori6c354da2010-04-26 23:33:39 -07002339 /* package */ SQLiteDatabase createPoolConnection(short connectionNum) {
Vasu Nori65a88832010-07-16 15:14:08 -07002340 SQLiteDatabase db = openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum);
2341 db.mParentConnObj = this;
2342 return db;
2343 }
2344
2345 private synchronized SQLiteDatabase getParentDbConnObj() {
2346 return mParentConnObj;
Vasu Nori6c354da2010-04-26 23:33:39 -07002347 }
2348
2349 private boolean isPooledConnection() {
2350 return this.mConnectionNum > 0;
2351 }
2352
Vasu Nori2827d6d2010-07-04 00:26:18 -07002353 /* package */ SQLiteDatabase getDbConnection(String sql) {
Vasu Nori6c354da2010-04-26 23:33:39 -07002354 verifyDbIsOpen();
Vasu Noribfe1dc22010-08-25 16:29:02 -07002355 // this method should always be called with main database connection handle.
2356 // the only time when it is called with pooled database connection handle is
2357 // corruption occurs while trying to open a pooled database connection handle.
2358 // in that case, simply return 'this' handle
Vasu Nori65a88832010-07-16 15:14:08 -07002359 if (isPooledConnection()) {
Vasu Noribfe1dc22010-08-25 16:29:02 -07002360 return this;
Vasu Nori65a88832010-07-16 15:14:08 -07002361 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002362
2363 // use the current connection handle if
Vasu Norice38b982010-07-22 13:57:13 -07002364 // 1. if the caller is part of the ongoing transaction, if any
Vasu Nori65a88832010-07-16 15:14:08 -07002365 // 2. OR, if there is NO connection handle pool setup
Vasu Norice38b982010-07-22 13:57:13 -07002366 if (amIInTransaction() || mConnectionPool == null) {
Vasu Nori65a88832010-07-16 15:14:08 -07002367 return this;
Vasu Nori6c354da2010-04-26 23:33:39 -07002368 } else {
2369 // get a connection handle from the pool
2370 if (Log.isLoggable(TAG, Log.DEBUG)) {
2371 assert mConnectionPool != null;
Vasu Norice38b982010-07-22 13:57:13 -07002372 Log.i(TAG, mConnectionPool.toString());
Vasu Nori6c354da2010-04-26 23:33:39 -07002373 }
Vasu Nori65a88832010-07-16 15:14:08 -07002374 return mConnectionPool.get(sql);
Vasu Nori6c354da2010-04-26 23:33:39 -07002375 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002376 }
2377
2378 private void releaseDbConnection(SQLiteDatabase db) {
2379 // ignore this release call if
2380 // 1. the database is closed
2381 // 2. OR, if db is NOT a pooled connection handle
2382 // 3. OR, if the database being released is same as 'this' (this condition means
2383 // that we should always be releasing a pooled connection handle by calling this method
2384 // from the 'main' connection handle
2385 if (!isOpen() || !db.isPooledConnection() || (db == this)) {
2386 return;
2387 }
2388 if (Log.isLoggable(TAG, Log.DEBUG)) {
2389 assert isPooledConnection();
2390 assert mConnectionPool != null;
2391 Log.d(TAG, "releaseDbConnection threadid = " + Thread.currentThread().getId() +
2392 ", releasing # " + db.mConnectionNum + ", " + getPath());
2393 }
2394 mConnectionPool.release(db);
2395 }
2396
Vasu Norif3cf8a42010-03-23 11:41:44 -07002397 /**
2398 * this method is used to collect data about ALL open databases in the current process.
Vasu Nori0732f792010-07-29 17:24:12 -07002399 * bugreport is a user of this data.
Vasu Norif3cf8a42010-03-23 11:41:44 -07002400 */
Vasu Noric3849202010-03-09 10:47:25 -08002401 /* package */ static ArrayList<DbStats> getDbStats() {
2402 ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
Vasu Nori5a049b02010-09-24 09:26:43 -07002403// // make a local copy of mActiveDatabases - so that this method is not competing
2404// // for synchronization lock on mActiveDatabases
2405// ArrayList<WeakReference<SQLiteDatabase>> tempList;
2406// synchronized(mActiveDatabases) {
2407// tempList = (ArrayList<WeakReference<SQLiteDatabase>>)mActiveDatabases.clone();
2408// }
2409// for (WeakReference<SQLiteDatabase> w : tempList) {
2410// SQLiteDatabase db = w.get();
2411// if (db == null || !db.isOpen()) {
2412// continue;
2413// }
2414//
2415// synchronized (db) {
2416// try {
2417// // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
2418// int lookasideUsed = db.native_getDbLookaside();
2419//
2420// // get the lastnode of the dbname
2421// String path = db.getPath();
2422// int indx = path.lastIndexOf("/");
2423// String lastnode = path.substring((indx != -1) ? ++indx : 0);
2424//
2425// // get list of attached dbs and for each db, get its size and pagesize
2426// ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs();
2427// if (attachedDbs == null) {
2428// continue;
2429// }
2430// for (int i = 0; i < attachedDbs.size(); i++) {
2431// Pair<String, String> p = attachedDbs.get(i);
2432// long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first
2433// + ".page_count;", null);
2434//
2435// // first entry in the attached db list is always the main database
2436// // don't worry about prefixing the dbname with "main"
2437// String dbName;
2438// if (i == 0) {
2439// dbName = lastnode;
2440// } else {
2441// // lookaside is only relevant for the main db
2442// lookasideUsed = 0;
2443// dbName = " (attached) " + p.first;
2444// // if the attached db has a path, attach the lastnode from the path to above
2445// if (p.second.trim().length() > 0) {
2446// int idx = p.second.lastIndexOf("/");
2447// dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
2448// }
2449// }
2450// if (pageCount > 0) {
2451// dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
2452// lookasideUsed, db.getCacheHitNum(), db.getCacheMissNum(),
2453// db.getCachesize()));
2454// }
2455// }
2456// // if there are pooled connections, return the cache stats for them also.
2457// if (db.mConnectionPool != null) {
2458// for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) {
2459// dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") "
2460// + lastnode, 0, 0, 0, pDb.getCacheHitNum(),
2461// pDb.getCacheMissNum(), pDb.getCachesize()));
2462// }
2463// }
2464// } catch (SQLiteException e) {
2465// // ignore. we don't care about exceptions when we are taking adb
2466// // bugreport!
2467// }
2468// }
2469// }
Vasu Noric3849202010-03-09 10:47:25 -08002470 return dbStatsList;
2471 }
2472
2473 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002474 * Returns list of full pathnames of all attached databases including the main database
2475 * by executing 'pragma database_list' on the database.
2476 *
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002477 * @return ArrayList of pairs of (database name, database file path) or null if the database
2478 * is not open.
Vasu Noric3849202010-03-09 10:47:25 -08002479 */
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002480 public ArrayList<Pair<String, String>> getAttachedDbs() {
2481 if (!isOpen()) {
Vasu Norif3cf8a42010-03-23 11:41:44 -07002482 return null;
2483 }
Vasu Noric3849202010-03-09 10:47:25 -08002484 ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002485 Cursor c = null;
2486 try {
2487 c = rawQuery("pragma database_list;", null);
2488 while (c.moveToNext()) {
2489 // sqlite returns a row for each database in the returned list of databases.
2490 // in each row,
2491 // 1st column is the database name such as main, or the database
2492 // name specified on the "ATTACH" command
2493 // 2nd column is the database file path.
2494 attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
2495 }
2496 } finally {
2497 if (c != null) {
2498 c.close();
2499 }
Vasu Noric3849202010-03-09 10:47:25 -08002500 }
Vasu Noric3849202010-03-09 10:47:25 -08002501 return attachedDbs;
2502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002505 * Runs 'pragma integrity_check' on the given database (and all the attached databases)
2506 * and returns true if the given database (and all its attached databases) pass integrity_check,
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002507 * false otherwise.
Vasu Noriccd95442010-05-28 17:04:16 -07002508 *<p>
2509 * If the result is false, then this method logs the errors reported by the integrity_check
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002510 * command execution.
Vasu Noriccd95442010-05-28 17:04:16 -07002511 *<p>
2512 * Note that 'pragma integrity_check' on a database can take a long time.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002513 *
2514 * @return true if the given database (and all its attached databases) pass integrity_check,
Vasu Noriccd95442010-05-28 17:04:16 -07002515 * false otherwise.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002516 */
2517 public boolean isDatabaseIntegrityOk() {
Vasu Noriccd95442010-05-28 17:04:16 -07002518 verifyDbIsOpen();
Vasu Noribfe1dc22010-08-25 16:29:02 -07002519 ArrayList<Pair<String, String>> attachedDbs = null;
2520 try {
2521 attachedDbs = getAttachedDbs();
2522 if (attachedDbs == null) {
2523 throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
2524 "be retrieved. probably because the database is closed");
2525 }
2526 } catch (SQLiteException e) {
2527 // can't get attachedDb list. do integrity check on the main database
2528 attachedDbs = new ArrayList<Pair<String, String>>();
2529 attachedDbs.add(new Pair<String, String>("main", this.mPath));
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002530 }
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002531 for (int i = 0; i < attachedDbs.size(); i++) {
2532 Pair<String, String> p = attachedDbs.get(i);
2533 SQLiteStatement prog = null;
2534 try {
2535 prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);");
2536 String rslt = prog.simpleQueryForString();
2537 if (!rslt.equalsIgnoreCase("ok")) {
2538 // integrity_checker failed on main or attached databases
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002539 Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt);
Vasu Noribfe1dc22010-08-25 16:29:02 -07002540 return false;
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002541 }
2542 } finally {
2543 if (prog != null) prog.close();
2544 }
2545 }
Vasu Noribfe1dc22010-08-25 16:29:02 -07002546 return true;
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002547 }
2548
2549 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 * Native call to open the database.
2551 *
2552 * @param path The full path to the database
2553 */
2554 private native void dbopen(String path, int flags);
2555
2556 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002557 * Native call to setup tracing of all SQL statements
Vasu Nori3ef94e22010-02-05 14:49:04 -08002558 *
2559 * @param path the full path to the database
Vasu Nori6c354da2010-04-26 23:33:39 -07002560 * @param connectionNum connection number: 0 - N, where the main database
2561 * connection handle is numbered 0 and the connection handles in the connection
2562 * pool are numbered 1..N.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002563 */
Vasu Nori6c354da2010-04-26 23:33:39 -07002564 private native void enableSqlTracing(String path, short connectionNum);
Vasu Nori3ef94e22010-02-05 14:49:04 -08002565
2566 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002567 * Native call to setup profiling of all SQL statements.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002568 * currently, sqlite's profiling = printing of execution-time
Vasu Noriccd95442010-05-28 17:04:16 -07002569 * (wall-clock time) of each of the SQL statements, as they
Vasu Nori3ef94e22010-02-05 14:49:04 -08002570 * are executed.
2571 *
2572 * @param path the full path to the database
Vasu Nori6c354da2010-04-26 23:33:39 -07002573 * @param connectionNum connection number: 0 - N, where the main database
2574 * connection handle is numbered 0 and the connection handles in the connection
2575 * pool are numbered 1..N.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002576 */
Vasu Nori6c354da2010-04-26 23:33:39 -07002577 private native void enableSqlProfiling(String path, short connectionNum);
Vasu Nori3ef94e22010-02-05 14:49:04 -08002578
2579 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 * Native call to set the locale. {@link #lock} must be held when calling
2581 * this method.
2582 * @throws SQLException
2583 */
Vasu Nori0732f792010-07-29 17:24:12 -07002584 private native void native_setLocale(String loc, int flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585
2586 /**
Vasu Noric3849202010-03-09 10:47:25 -08002587 * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here
2588 * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html
2589 * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED
2590 */
2591 private native int native_getDbLookaside();
Vasu Nori6f37f832010-05-19 11:53:25 -07002592
2593 /**
2594 * finalizes the given statement id.
2595 *
2596 * @param statementId statement to be finzlied by sqlite
2597 */
2598 private final native void native_finalize(int statementId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599}