blob: e3c25ec0ddb91f424d814fe155cabe299b003265 [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
Vasu Nori5a03f362009-10-20 15:16:35 -070019import com.google.android.collect.Maps;
20
Dan Egnor12311952009-11-23 14:47:45 -080021import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.ContentValues;
23import android.database.Cursor;
24import android.database.DatabaseUtils;
25import android.database.SQLException;
26import android.os.Debug;
27import android.os.SystemClock;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070028import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.text.TextUtils;
30import android.util.Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.EventLog;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070032import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34import java.io.File;
Vasu Nori5a03f362009-10-20 15:16:35 -070035import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import java.util.HashMap;
37import java.util.Iterator;
38import java.util.Locale;
39import java.util.Map;
Dan Egnor12311952009-11-23 14:47:45 -080040import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import java.util.Set;
42import java.util.WeakHashMap;
43import java.util.concurrent.locks.ReentrantLock;
44
45/**
46 * Exposes methods to manage a SQLite database.
47 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
48 * perform other common database management tasks.
49 * <p>See the Notepad sample application in the SDK for an example of creating
50 * and managing a database.
51 * <p> Database names must be unique within an application, not across all
52 * applications.
53 *
54 * <h3>Localized Collation - ORDER BY</h3>
55 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
56 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
57 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
58 * is the Unicode Collation Algorithm and not tailored to the current locale.
59 */
60public class SQLiteDatabase extends SQLiteClosable {
61 private static final String TAG = "Database";
Jeff Hamilton082c2af2009-09-29 11:49:51 -070062 private static final int EVENT_DB_OPERATION = 52000;
63 private static final int EVENT_DB_CORRUPT = 75004;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65 /**
66 * Algorithms used in ON CONFLICT clause
67 * http://www.sqlite.org/lang_conflict.html
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 */
Vasu Nori6eb7c452010-01-27 14:31:24 -080069 public static final class ConflictAlgorithm {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070071 * When a constraint violation occurs, an immediate ROLLBACK occurs,
72 * thus ending the current transaction, and the command aborts with a
73 * return code of SQLITE_CONSTRAINT. If no transaction is active
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 * (other than the implied transaction that is created on every command)
75 * then this algorithm works the same as ABORT.
76 */
Vasu Nori6eb7c452010-01-27 14:31:24 -080077 public static final int ROLLBACK = 1;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070080 * When a constraint violation occurs,no ROLLBACK is executed
81 * so changes from prior commands within the same transaction
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 * are preserved. This is the default behavior.
83 */
Vasu Nori6eb7c452010-01-27 14:31:24 -080084 public static final int ABORT = 2;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070087 * When a constraint violation occurs, the command aborts with a return
88 * code SQLITE_CONSTRAINT. But any changes to the database that
89 * the command made prior to encountering the constraint violation
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 * are preserved and are not backed out.
91 */
Vasu Nori6eb7c452010-01-27 14:31:24 -080092 public static final int FAIL = 3;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070095 * When a constraint violation occurs, the one row that contains
96 * the constraint violation is not inserted or changed.
97 * But the command continues executing normally. Other rows before and
98 * after the row that contained the constraint violation continue to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 * inserted or updated normally. No error is returned.
100 */
Vasu Nori6eb7c452010-01-27 14:31:24 -0800101 public static final int IGNORE = 4;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 /**
104 * When a UNIQUE constraint violation occurs, the pre-existing rows that
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700105 * are causing the constraint violation are removed prior to inserting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 * or updating the current row. Thus the insert or update always occurs.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700107 * The command continues executing normally. No error is returned.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 * If a NOT NULL constraint violation occurs, the NULL value is replaced
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700109 * by the default value for that column. If the column has no default
110 * value, then the ABORT algorithm is used. If a CHECK constraint
111 * violation occurs then the IGNORE algorithm is used. When this conflict
112 * resolution strategy deletes rows in order to satisfy a constraint,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 * it does not invoke delete triggers on those rows.
114 * This behavior might change in a future release.
115 */
Vasu Nori6eb7c452010-01-27 14:31:24 -0800116 public static final int REPLACE = 5;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700117
Vasu Nori6eb7c452010-01-27 14:31:24 -0800118 /**
119 * use the following when no conflict action is specified.
120 */
121 public static final int NONE = 0;
122 private static final String[] VALUES = new String[]
123 {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
124
125 private ConflictAlgorithm() {} // disable instantiation of this class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 /**
129 * Maximum Length Of A LIKE Or GLOB Pattern
130 * The pattern matching algorithm used in the default LIKE and GLOB implementation
131 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
132 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
133 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
134 * The default value of this limit is 50000. A modern workstation can evaluate
135 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
136 * The denial of service problem only comes into play when the pattern length gets
137 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
138 * are at most a few dozen bytes in length, paranoid application developers may
139 * want to reduce this parameter to something in the range of a few hundred
140 * if they know that external users are able to generate arbitrary patterns.
141 */
142 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
143
144 /**
145 * Flag for {@link #openDatabase} to open the database for reading and writing.
146 * If the disk is full, this may fail even before you actually write anything.
147 *
148 * {@more} Note that the value of this flag is 0, so it is the default.
149 */
150 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
151
152 /**
153 * Flag for {@link #openDatabase} to open the database for reading only.
154 * This is the only reliable way to open a database if the disk may be full.
155 */
156 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
157
158 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
159
160 /**
161 * Flag for {@link #openDatabase} to open the database without support for localized collators.
162 *
163 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
164 * You must be consistent when using this flag to use the setting the database was
165 * created with. If this is set, {@link #setLocale} will do nothing.
166 */
167 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
168
169 /**
170 * Flag for {@link #openDatabase} to create the database file if it does not already exist.
171 */
172 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
173
174 /**
175 * Indicates whether the most-recently started transaction has been marked as successful.
176 */
177 private boolean mInnerTransactionIsSuccessful;
178
179 /**
180 * Valid during the life of a transaction, and indicates whether the entire transaction (the
181 * outer one and all of the inner ones) so far has been successful.
182 */
183 private boolean mTransactionIsSuccessful;
184
Fred Quintanac4516a72009-09-03 12:14:06 -0700185 /**
186 * Valid during the life of a transaction.
187 */
188 private SQLiteTransactionListener mTransactionListener;
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 /** Synchronize on this when accessing the database */
191 private final ReentrantLock mLock = new ReentrantLock(true);
192
193 private long mLockAcquiredWallTime = 0L;
194 private long mLockAcquiredThreadTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 // limit the frequency of complaints about each database to one within 20 sec
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700197 // unless run command adb shell setprop log.tag.Database VERBOSE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
199 /** If the lock is held this long then a warning will be printed when it is released. */
200 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
201 private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
202 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
203
Dmitri Plotnikovb43b58d2009-09-09 18:10:42 -0700204 private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 private long mLastLockMessageTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700207
Dan Egnor12311952009-11-23 14:47:45 -0800208 // always log queries which take 100ms+; shorter queries are sampled accordingly
209 private static final int QUERY_LOG_TIME_IN_NANOS = 100 * 1000000;
210 private static final int QUERY_LOG_SQL_LENGTH = 64;
211 private final Random mRandom = new Random();
212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 /** Used by native code, do not rename */
214 /* package */ int mNativeHandle = 0;
215
216 /** Used to make temp table names unique */
217 /* package */ int mTempTableSequence = 0;
218
219 /** The path for the database file */
220 private String mPath;
221
222 /** The flags passed to open/create */
223 private int mFlags;
224
225 /** The optional factory to use when creating new Cursors */
226 private CursorFactory mFactory;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 private WeakHashMap<SQLiteClosable, Object> mPrograms;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700229
Vasu Nori5a03f362009-10-20 15:16:35 -0700230 /**
231 * for each instance of this class, a cache is maintained to store
232 * the compiled query statement ids returned by sqlite database.
233 * key = sql statement with "?" for bind args
234 * value = {@link SQLiteCompiledSql}
235 * If an application opens the database and keeps it open during its entire life, then
236 * there will not be an overhead of compilation of sql statements by sqlite.
237 *
238 * why is this cache NOT static? because sqlite attaches compiledsql statements to the
239 * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
240 * invoked.
241 *
242 * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
243 * (@link setMaxCacheSize(int)}). its default is 0 - i.e., no caching by default because
244 * most of the apps don't use "?" syntax in their sql, caching is not useful for them.
245 */
Vasu Norie495d1f2010-01-06 16:34:19 -0800246 /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap();
247 /**
248 * @hide
249 */
250 public static final int MAX_SQL_CACHE_SIZE = 250;
251 private int mMaxSqlCacheSize = MAX_SQL_CACHE_SIZE; // max cache size per Database instance
Vasu Norie9d92102010-01-20 15:07:26 -0800252 private int mCacheFullWarnings;
253 private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 5;
Vasu Nori5a03f362009-10-20 15:16:35 -0700254
255 /** maintain stats about number of cache hits and misses */
256 private int mNumCacheHits;
257 private int mNumCacheMisses;
258
259 /** the following 2 members maintain the time when a database is opened and closed */
260 private String mTimeOpened = null;
261 private String mTimeClosed = null;
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 private final RuntimeException mLeakedException;
264
Dmitri Plotnikov90142c92009-09-15 10:52:17 -0700265 // System property that enables logging of slow queries. Specify the threshold in ms.
266 private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
267 private final int mSlowQueryThreshold;
268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 /**
270 * @param closable
271 */
272 void addSQLiteClosable(SQLiteClosable closable) {
273 lock();
274 try {
275 mPrograms.put(closable, null);
276 } finally {
277 unlock();
278 }
279 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 void removeSQLiteClosable(SQLiteClosable closable) {
282 lock();
283 try {
284 mPrograms.remove(closable);
285 } finally {
286 unlock();
287 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700288 }
289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 @Override
291 protected void onAllReferencesReleased() {
292 if (isOpen()) {
Vasu Nori5a03f362009-10-20 15:16:35 -0700293 if (SQLiteDebug.DEBUG_SQL_CACHE) {
294 mTimeClosed = getTime();
295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 dbclose();
297 }
298 }
299
300 /**
301 * Attempts to release memory that SQLite holds but does not require to
302 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700303 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 * @return the number of bytes actually released
305 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700306 static public native int releaseMemory();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307
308 /**
309 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
310 * around critical sections. This is pretty expensive, so if you know that your
311 * DB will only be used by a single thread then you should set this to false.
312 * The default is true.
313 * @param lockingEnabled set to true to enable locks, false otherwise
314 */
315 public void setLockingEnabled(boolean lockingEnabled) {
316 mLockingEnabled = lockingEnabled;
317 }
318
319 /**
320 * If set then the SQLiteDatabase is made thread-safe by using locks
321 * around critical sections
322 */
323 private boolean mLockingEnabled = true;
324
325 /* package */ void onCorruption() {
326 try {
327 // Close the database (if we can), which will cause subsequent operations to fail.
328 close();
329 } finally {
330 Log.e(TAG, "Removing corrupt database: " + mPath);
Vasu Noridd1b39b2010-01-08 10:11:24 -0800331 EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 // Delete the corrupt file. Don't re-create it now -- that would just confuse people
333 // -- but the next time someone tries to open it, they can set it up from scratch.
334 new File(mPath).delete();
335 }
336 }
337
338 /**
339 * Locks the database for exclusive access. The database lock must be held when
340 * touch the native sqlite3* object since it is single threaded and uses
341 * a polling lock contention algorithm. The lock is recursive, and may be acquired
342 * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700343 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 * @see #unlock()
345 */
346 /* package */ void lock() {
347 if (!mLockingEnabled) return;
348 mLock.lock();
349 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
350 if (mLock.getHoldCount() == 1) {
351 // Use elapsed real-time since the CPU may sleep when waiting for IO
352 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
353 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
354 }
355 }
356 }
357
358 /**
359 * Locks the database for exclusive access. The database lock must be held when
360 * touch the native sqlite3* object since it is single threaded and uses
361 * a polling lock contention algorithm. The lock is recursive, and may be acquired
362 * multiple times by the same thread.
363 *
364 * @see #unlockForced()
365 */
366 private void lockForced() {
367 mLock.lock();
368 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
369 if (mLock.getHoldCount() == 1) {
370 // Use elapsed real-time since the CPU may sleep when waiting for IO
371 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
372 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
373 }
374 }
375 }
376
377 /**
378 * Releases the database lock. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700379 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 * @see #unlock()
381 */
382 /* package */ void unlock() {
383 if (!mLockingEnabled) return;
384 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
385 if (mLock.getHoldCount() == 1) {
386 checkLockHoldTime();
387 }
388 }
389 mLock.unlock();
390 }
391
392 /**
393 * Releases the database lock.
394 *
395 * @see #unlockForced()
396 */
397 private void unlockForced() {
398 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
399 if (mLock.getHoldCount() == 1) {
400 checkLockHoldTime();
401 }
402 }
403 mLock.unlock();
404 }
405
406 private void checkLockHoldTime() {
407 // Use elapsed real-time since the CPU may sleep when waiting for IO
408 long elapsedTime = SystemClock.elapsedRealtime();
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700409 long lockedTime = elapsedTime - mLockAcquiredWallTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
411 !Log.isLoggable(TAG, Log.VERBOSE) &&
412 (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
413 return;
414 }
415 if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
416 int threadTime = (int)
417 ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
418 if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
419 lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
420 mLastLockMessageTime = elapsedTime;
421 String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
422 + threadTime + "ms";
423 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
424 Log.d(TAG, msg, new Exception());
425 } else {
426 Log.d(TAG, msg);
427 }
428 }
429 }
430 }
431
432 /**
433 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
434 * the work done in that transaction and all of the nested transactions will be committed or
435 * rolled back. The changes will be rolled back if any transaction is ended without being
436 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
437 *
438 * <p>Here is the standard idiom for transactions:
439 *
440 * <pre>
441 * db.beginTransaction();
442 * try {
443 * ...
444 * db.setTransactionSuccessful();
445 * } finally {
446 * db.endTransaction();
447 * }
448 * </pre>
449 */
450 public void beginTransaction() {
Fred Quintanac4516a72009-09-03 12:14:06 -0700451 beginTransactionWithListener(null /* transactionStatusCallback */);
452 }
453
454 /**
455 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
456 * the work done in that transaction and all of the nested transactions will be committed or
457 * rolled back. The changes will be rolled back if any transaction is ended without being
458 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
459 *
460 * <p>Here is the standard idiom for transactions:
461 *
462 * <pre>
463 * db.beginTransactionWithListener(listener);
464 * try {
465 * ...
466 * db.setTransactionSuccessful();
467 * } finally {
468 * db.endTransaction();
469 * }
470 * </pre>
471 * @param transactionListener listener that should be notified when the transaction begins,
472 * commits, or is rolled back, either explicitly or by a call to
473 * {@link #yieldIfContendedSafely}.
474 */
475 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 lockForced();
477 boolean ok = false;
478 try {
479 // If this thread already had the lock then get out
480 if (mLock.getHoldCount() > 1) {
481 if (mInnerTransactionIsSuccessful) {
482 String msg = "Cannot call beginTransaction between "
483 + "calling setTransactionSuccessful and endTransaction";
484 IllegalStateException e = new IllegalStateException(msg);
485 Log.e(TAG, "beginTransaction() failed", e);
486 throw e;
487 }
488 ok = true;
489 return;
490 }
491
492 // This thread didn't already have the lock, so begin a database
493 // transaction now.
494 execSQL("BEGIN EXCLUSIVE;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700495 mTransactionListener = transactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 mTransactionIsSuccessful = true;
497 mInnerTransactionIsSuccessful = false;
Fred Quintanac4516a72009-09-03 12:14:06 -0700498 if (transactionListener != null) {
499 try {
500 transactionListener.onBegin();
501 } catch (RuntimeException e) {
502 execSQL("ROLLBACK;");
503 throw e;
504 }
505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 ok = true;
507 } finally {
508 if (!ok) {
509 // beginTransaction is called before the try block so we must release the lock in
510 // the case of failure.
511 unlockForced();
512 }
513 }
514 }
515
516 /**
517 * End a transaction. See beginTransaction for notes about how to use this and when transactions
518 * are committed and rolled back.
519 */
520 public void endTransaction() {
521 if (!mLock.isHeldByCurrentThread()) {
522 throw new IllegalStateException("no transaction pending");
523 }
524 try {
525 if (mInnerTransactionIsSuccessful) {
526 mInnerTransactionIsSuccessful = false;
527 } else {
528 mTransactionIsSuccessful = false;
529 }
530 if (mLock.getHoldCount() != 1) {
531 return;
532 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700533 RuntimeException savedException = null;
534 if (mTransactionListener != null) {
535 try {
536 if (mTransactionIsSuccessful) {
537 mTransactionListener.onCommit();
538 } else {
539 mTransactionListener.onRollback();
540 }
541 } catch (RuntimeException e) {
542 savedException = e;
543 mTransactionIsSuccessful = false;
544 }
545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 if (mTransactionIsSuccessful) {
547 execSQL("COMMIT;");
548 } else {
549 try {
550 execSQL("ROLLBACK;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700551 if (savedException != null) {
552 throw savedException;
553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 } catch (SQLException e) {
555 if (Config.LOGD) {
556 Log.d(TAG, "exception during rollback, maybe the DB previously "
557 + "performed an auto-rollback");
558 }
559 }
560 }
561 } finally {
Fred Quintanac4516a72009-09-03 12:14:06 -0700562 mTransactionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 unlockForced();
564 if (Config.LOGV) {
565 Log.v(TAG, "unlocked " + Thread.currentThread()
566 + ", holdCount is " + mLock.getHoldCount());
567 }
568 }
569 }
570
571 /**
572 * Marks the current transaction as successful. Do not do any more database work between
573 * calling this and calling endTransaction. Do as little non-database work as possible in that
574 * situation too. If any errors are encountered between this and endTransaction the transaction
575 * will still be committed.
576 *
577 * @throws IllegalStateException if the current thread is not in a transaction or the
578 * transaction is already marked as successful.
579 */
580 public void setTransactionSuccessful() {
581 if (!mLock.isHeldByCurrentThread()) {
582 throw new IllegalStateException("no transaction pending");
583 }
584 if (mInnerTransactionIsSuccessful) {
585 throw new IllegalStateException(
586 "setTransactionSuccessful may only be called once per call to beginTransaction");
587 }
588 mInnerTransactionIsSuccessful = true;
589 }
590
591 /**
592 * return true if there is a transaction pending
593 */
594 public boolean inTransaction() {
595 return mLock.getHoldCount() > 0;
596 }
597
598 /**
599 * Checks if the database lock is held by this thread.
600 *
601 * @return true, if this thread is holding the database lock.
602 */
603 public boolean isDbLockedByCurrentThread() {
604 return mLock.isHeldByCurrentThread();
605 }
606
607 /**
608 * Checks if the database is locked by another thread. This is
609 * just an estimate, since this status can change at any time,
610 * including after the call is made but before the result has
611 * been acted upon.
612 *
613 * @return true, if the database is locked by another thread
614 */
615 public boolean isDbLockedByOtherThreads() {
616 return !mLock.isHeldByCurrentThread() && mLock.isLocked();
617 }
618
619 /**
620 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
621 * successful so far. Do not call setTransactionSuccessful before calling this. When this
622 * returns a new transaction will have been created but not marked as successful.
623 * @return true if the transaction was yielded
624 * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
625 * will not be yielded. Use yieldIfContendedSafely instead.
626 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700627 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700629 return yieldIfContendedHelper(false /* do not check yielding */,
630 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
632
633 /**
634 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
635 * successful so far. Do not call setTransactionSuccessful before calling this. When this
636 * returns a new transaction will have been created but not marked as successful. This assumes
637 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700638 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 * @return true if the transaction was yielded
640 */
641 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700642 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
644
Fred Quintana5c7aede2009-08-27 21:41:27 -0700645 /**
646 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
647 * successful so far. Do not call setTransactionSuccessful before calling this. When this
648 * returns a new transaction will have been created but not marked as successful. This assumes
649 * that there are no nested transactions (beginTransaction has only been called once) and will
650 * throw an exception if that is not the case.
651 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
652 * the lock was actually yielded. This will allow other background threads to make some
653 * more progress than they would if we started the transaction immediately.
654 * @return true if the transaction was yielded
655 */
656 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
657 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
658 }
659
660 private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 if (mLock.getQueueLength() == 0) {
662 // Reset the lock acquire time since we know that the thread was willing to yield
663 // the lock at this time.
664 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
665 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
666 return false;
667 }
668 setTransactionSuccessful();
Fred Quintanac4516a72009-09-03 12:14:06 -0700669 SQLiteTransactionListener transactionListener = mTransactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 endTransaction();
671 if (checkFullyYielded) {
672 if (this.isDbLockedByCurrentThread()) {
673 throw new IllegalStateException(
674 "Db locked more than once. yielfIfContended cannot yield");
675 }
676 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700677 if (sleepAfterYieldDelay > 0) {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700678 // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
679 // check if anyone is using the database. If the database is not contended,
680 // retake the lock and return.
681 long remainingDelay = sleepAfterYieldDelay;
682 while (remainingDelay > 0) {
683 try {
684 Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
685 remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
686 } catch (InterruptedException e) {
687 Thread.interrupted();
688 }
689 remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
690 if (mLock.getQueueLength() == 0) {
691 break;
692 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700693 }
694 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700695 beginTransactionWithListener(transactionListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 return true;
697 }
698
699 /** Maps table names to info about what to which _sync_time column to set
700 * to NULL on an update. This is used to support syncing. */
701 private final Map<String, SyncUpdateInfo> mSyncUpdateInfo =
702 new HashMap<String, SyncUpdateInfo>();
703
704 public Map<String, String> getSyncedTables() {
705 synchronized(mSyncUpdateInfo) {
706 HashMap<String, String> tables = new HashMap<String, String>();
707 for (String table : mSyncUpdateInfo.keySet()) {
708 SyncUpdateInfo info = mSyncUpdateInfo.get(table);
709 if (info.deletedTable != null) {
710 tables.put(table, info.deletedTable);
711 }
712 }
713 return tables;
714 }
715 }
716
717 /**
718 * Internal class used to keep track what needs to be marked as changed
719 * when an update occurs. This is used for syncing, so the sync engine
720 * knows what data has been updated locally.
721 */
722 static private class SyncUpdateInfo {
723 /**
724 * Creates the SyncUpdateInfo class.
725 *
726 * @param masterTable The table to set _sync_time to NULL in
727 * @param deletedTable The deleted table that corresponds to the
728 * master table
729 * @param foreignKey The key that refers to the primary key in table
730 */
731 SyncUpdateInfo(String masterTable, String deletedTable,
732 String foreignKey) {
733 this.masterTable = masterTable;
734 this.deletedTable = deletedTable;
735 this.foreignKey = foreignKey;
736 }
737
738 /** The table containing the _sync_time column */
739 String masterTable;
740
741 /** The deleted table that corresponds to the master table */
742 String deletedTable;
743
744 /** The key in the local table the row in table. It may be _id, if table
745 * is the local table. */
746 String foreignKey;
747 }
748
749 /**
750 * Used to allow returning sub-classes of {@link Cursor} when calling query.
751 */
752 public interface CursorFactory {
753 /**
754 * See
755 * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver,
756 * String, SQLiteQuery)}.
757 */
758 public Cursor newCursor(SQLiteDatabase db,
759 SQLiteCursorDriver masterQuery, String editTable,
760 SQLiteQuery query);
761 }
762
763 /**
764 * Open the database according to the flags {@link #OPEN_READWRITE}
765 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
766 *
767 * <p>Sets the locale of the database to the the system's current locale.
768 * Call {@link #setLocale} if you would like something else.</p>
769 *
770 * @param path to database file to open and/or create
771 * @param factory an optional factory class that is called to instantiate a
772 * cursor when query is called, or null for default
773 * @param flags to control database access mode
774 * @return the newly opened database
775 * @throws SQLiteException if the database cannot be opened
776 */
777 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
778 SQLiteDatabase db = null;
779 try {
780 // Open the database.
781 return new SQLiteDatabase(path, factory, flags);
782 } catch (SQLiteDatabaseCorruptException e) {
783 // Try to recover from this, if we can.
784 // TODO: should we do this for other open failures?
785 Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
Jeff Hamilton082c2af2009-09-29 11:49:51 -0700786 EventLog.writeEvent(EVENT_DB_CORRUPT, path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 new File(path).delete();
788 return new SQLiteDatabase(path, factory, flags);
789 }
790 }
791
792 /**
793 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
794 */
795 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
796 return openOrCreateDatabase(file.getPath(), factory);
797 }
798
799 /**
800 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
801 */
802 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
803 return openDatabase(path, factory, CREATE_IF_NECESSARY);
804 }
805
806 /**
807 * Create a memory backed SQLite database. Its contents will be destroyed
808 * when the database is closed.
809 *
810 * <p>Sets the locale of the database to the the system's current locale.
811 * Call {@link #setLocale} if you would like something else.</p>
812 *
813 * @param factory an optional factory class that is called to instantiate a
814 * cursor when query is called
815 * @return a SQLiteDatabase object, or null if the database can't be created
816 */
817 public static SQLiteDatabase create(CursorFactory factory) {
818 // This is a magic string with special meaning for SQLite.
819 return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
820 }
821
822 /**
823 * Close the database.
824 */
825 public void close() {
826 lock();
827 try {
828 closeClosable();
829 releaseReference();
830 } finally {
831 unlock();
832 }
833 }
834
835 private void closeClosable() {
Vasu Norie495d1f2010-01-06 16:34:19 -0800836 /* deallocate all compiled sql statement objects from mCompiledQueries cache.
837 * this should be done before de-referencing all {@link SQLiteClosable} objects
838 * from this database object because calling
839 * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
840 * to be closed. sqlite doesn't let a database close if there are
841 * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries.
842 */
843 deallocCachedSqlStatements();
844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
846 while (iter.hasNext()) {
847 Map.Entry<SQLiteClosable, Object> entry = iter.next();
848 SQLiteClosable program = entry.getKey();
849 if (program != null) {
850 program.onAllReferencesReleasedFromContainer();
851 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 /**
856 * Native call to close the database.
857 */
858 private native void dbclose();
859
860 /**
861 * Gets the database version.
862 *
863 * @return the database version
864 */
865 public int getVersion() {
866 SQLiteStatement prog = null;
867 lock();
868 try {
869 prog = new SQLiteStatement(this, "PRAGMA user_version;");
870 long version = prog.simpleQueryForLong();
871 return (int) version;
872 } finally {
873 if (prog != null) prog.close();
874 unlock();
875 }
876 }
877
878 /**
879 * Sets the database version.
880 *
881 * @param version the new database version
882 */
883 public void setVersion(int version) {
884 execSQL("PRAGMA user_version = " + version);
885 }
886
887 /**
888 * Returns the maximum size the database may grow to.
889 *
890 * @return the new maximum database size
891 */
892 public long getMaximumSize() {
893 SQLiteStatement prog = null;
894 lock();
895 try {
896 prog = new SQLiteStatement(this,
897 "PRAGMA max_page_count;");
898 long pageCount = prog.simpleQueryForLong();
899 return pageCount * getPageSize();
900 } finally {
901 if (prog != null) prog.close();
902 unlock();
903 }
904 }
905
906 /**
907 * Sets the maximum size the database will grow to. The maximum size cannot
908 * be set below the current size.
909 *
910 * @param numBytes the maximum database size, in bytes
911 * @return the new maximum database size
912 */
913 public long setMaximumSize(long numBytes) {
914 SQLiteStatement prog = null;
915 lock();
916 try {
917 long pageSize = getPageSize();
918 long numPages = numBytes / pageSize;
919 // If numBytes isn't a multiple of pageSize, bump up a page
920 if ((numBytes % pageSize) != 0) {
921 numPages++;
922 }
923 prog = new SQLiteStatement(this,
924 "PRAGMA max_page_count = " + numPages);
925 long newPageCount = prog.simpleQueryForLong();
926 return newPageCount * pageSize;
927 } finally {
928 if (prog != null) prog.close();
929 unlock();
930 }
931 }
932
933 /**
934 * Returns the current database page size, in bytes.
935 *
936 * @return the database page size, in bytes
937 */
938 public long getPageSize() {
939 SQLiteStatement prog = null;
940 lock();
941 try {
942 prog = new SQLiteStatement(this,
943 "PRAGMA page_size;");
944 long size = prog.simpleQueryForLong();
945 return size;
946 } finally {
947 if (prog != null) prog.close();
948 unlock();
949 }
950 }
951
952 /**
953 * Sets the database page size. The page size must be a power of two. This
954 * method does not work if any data has been written to the database file,
955 * and must be called right after the database has been created.
956 *
957 * @param numBytes the database page size, in bytes
958 */
959 public void setPageSize(long numBytes) {
960 execSQL("PRAGMA page_size = " + numBytes);
961 }
962
963 /**
964 * Mark this table as syncable. When an update occurs in this table the
965 * _sync_dirty field will be set to ensure proper syncing operation.
966 *
967 * @param table the table to mark as syncable
968 * @param deletedTable The deleted table that corresponds to the
969 * syncable table
970 */
971 public void markTableSyncable(String table, String deletedTable) {
972 markTableSyncable(table, "_id", table, deletedTable);
973 }
974
975 /**
976 * Mark this table as syncable, with the _sync_dirty residing in another
977 * table. When an update occurs in this table the _sync_dirty field of the
978 * row in updateTable with the _id in foreignKey will be set to
979 * ensure proper syncing operation.
980 *
981 * @param table an update on this table will trigger a sync time removal
982 * @param foreignKey this is the column in table whose value is an _id in
983 * updateTable
984 * @param updateTable this is the table that will have its _sync_dirty
985 */
986 public void markTableSyncable(String table, String foreignKey,
987 String updateTable) {
988 markTableSyncable(table, foreignKey, updateTable, null);
989 }
990
991 /**
992 * Mark this table as syncable, with the _sync_dirty residing in another
993 * table. When an update occurs in this table the _sync_dirty field of the
994 * row in updateTable with the _id in foreignKey will be set to
995 * ensure proper syncing operation.
996 *
997 * @param table an update on this table will trigger a sync time removal
998 * @param foreignKey this is the column in table whose value is an _id in
999 * updateTable
1000 * @param updateTable this is the table that will have its _sync_dirty
1001 * @param deletedTable The deleted table that corresponds to the
1002 * updateTable
1003 */
1004 private void markTableSyncable(String table, String foreignKey,
1005 String updateTable, String deletedTable) {
1006 lock();
1007 try {
1008 native_execSQL("SELECT _sync_dirty FROM " + updateTable
1009 + " LIMIT 0");
1010 native_execSQL("SELECT " + foreignKey + " FROM " + table
1011 + " LIMIT 0");
1012 } finally {
1013 unlock();
1014 }
1015
1016 SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable,
1017 foreignKey);
1018 synchronized (mSyncUpdateInfo) {
1019 mSyncUpdateInfo.put(table, info);
1020 }
1021 }
1022
1023 /**
1024 * Call for each row that is updated in a cursor.
1025 *
1026 * @param table the table the row is in
1027 * @param rowId the row ID of the updated row
1028 */
1029 /* package */ void rowUpdated(String table, long rowId) {
1030 SyncUpdateInfo info;
1031 synchronized (mSyncUpdateInfo) {
1032 info = mSyncUpdateInfo.get(table);
1033 }
1034 if (info != null) {
1035 execSQL("UPDATE " + info.masterTable
1036 + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
1037 + " FROM " + table + " WHERE _id=" + rowId + ")");
1038 }
1039 }
1040
1041 /**
1042 * Finds the name of the first table, which is editable.
1043 *
1044 * @param tables a list of tables
1045 * @return the first table listed
1046 */
1047 public static String findEditTable(String tables) {
1048 if (!TextUtils.isEmpty(tables)) {
1049 // find the first word terminated by either a space or a comma
1050 int spacepos = tables.indexOf(' ');
1051 int commapos = tables.indexOf(',');
1052
1053 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1054 return tables.substring(0, spacepos);
1055 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1056 return tables.substring(0, commapos);
1057 }
1058 return tables;
1059 } else {
1060 throw new IllegalStateException("Invalid tables");
1061 }
1062 }
1063
1064 /**
1065 * Compiles an SQL statement into a reusable pre-compiled statement object.
1066 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1067 * statement and fill in those values with {@link SQLiteProgram#bindString}
1068 * and {@link SQLiteProgram#bindLong} each time you want to run the
1069 * statement. Statements may not return result sets larger than 1x1.
1070 *
1071 * @param sql The raw SQL statement, may contain ? for unknown values to be
1072 * bound later.
1073 * @return a pre-compiled statement object.
1074 */
1075 public SQLiteStatement compileStatement(String sql) throws SQLException {
1076 lock();
1077 try {
1078 return new SQLiteStatement(this, sql);
1079 } finally {
1080 unlock();
1081 }
1082 }
1083
1084 /**
1085 * Query the given URL, returning a {@link Cursor} over the result set.
1086 *
1087 * @param distinct true if you want each row to be unique, false otherwise.
1088 * @param table The table name to compile the query against.
1089 * @param columns A list of which columns to return. Passing null will
1090 * return all columns, which is discouraged to prevent reading
1091 * data from storage that isn't going to be used.
1092 * @param selection A filter declaring which rows to return, formatted as an
1093 * SQL WHERE clause (excluding the WHERE itself). Passing null
1094 * will return all rows for the given table.
1095 * @param selectionArgs You may include ?s in selection, which will be
1096 * replaced by the values from selectionArgs, in order that they
1097 * appear in the selection. The values will be bound as Strings.
1098 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1099 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1100 * will cause the rows to not be grouped.
1101 * @param having A filter declare which row groups to include in the cursor,
1102 * if row grouping is being used, formatted as an SQL HAVING
1103 * clause (excluding the HAVING itself). Passing null will cause
1104 * all row groups to be included, and is required when row
1105 * grouping is not being used.
1106 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1107 * (excluding the ORDER BY itself). Passing null will use the
1108 * default sort order, which may be unordered.
1109 * @param limit Limits the number of rows returned by the query,
1110 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1111 * @return A Cursor object, which is positioned before the first entry
1112 * @see Cursor
1113 */
1114 public Cursor query(boolean distinct, String table, String[] columns,
1115 String selection, String[] selectionArgs, String groupBy,
1116 String having, String orderBy, String limit) {
1117 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1118 groupBy, having, orderBy, limit);
1119 }
1120
1121 /**
1122 * Query the given URL, returning a {@link Cursor} over the result set.
1123 *
1124 * @param cursorFactory the cursor factory to use, or null for the default factory
1125 * @param distinct true if you want each row to be unique, false otherwise.
1126 * @param table The table name to compile the query against.
1127 * @param columns A list of which columns to return. Passing null will
1128 * return all columns, which is discouraged to prevent reading
1129 * data from storage that isn't going to be used.
1130 * @param selection A filter declaring which rows to return, formatted as an
1131 * SQL WHERE clause (excluding the WHERE itself). Passing null
1132 * will return all rows for the given table.
1133 * @param selectionArgs You may include ?s in selection, which will be
1134 * replaced by the values from selectionArgs, in order that they
1135 * appear in the selection. The values will be bound as Strings.
1136 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1137 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1138 * will cause the rows to not be grouped.
1139 * @param having A filter declare which row groups to include in the cursor,
1140 * if row grouping is being used, formatted as an SQL HAVING
1141 * clause (excluding the HAVING itself). Passing null will cause
1142 * all row groups to be included, and is required when row
1143 * grouping is not being used.
1144 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1145 * (excluding the ORDER BY itself). Passing null will use the
1146 * default sort order, which may be unordered.
1147 * @param limit Limits the number of rows returned by the query,
1148 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1149 * @return A Cursor object, which is positioned before the first entry
1150 * @see Cursor
1151 */
1152 public Cursor queryWithFactory(CursorFactory cursorFactory,
1153 boolean distinct, String table, String[] columns,
1154 String selection, String[] selectionArgs, String groupBy,
1155 String having, String orderBy, String limit) {
1156 String sql = SQLiteQueryBuilder.buildQueryString(
1157 distinct, table, columns, selection, groupBy, having, orderBy, limit);
1158
1159 return rawQueryWithFactory(
1160 cursorFactory, sql, selectionArgs, findEditTable(table));
1161 }
1162
1163 /**
1164 * Query the given table, returning a {@link Cursor} over the result set.
1165 *
1166 * @param table The table name to compile the query against.
1167 * @param columns A list of which columns to return. Passing null will
1168 * return all columns, which is discouraged to prevent reading
1169 * data from storage that isn't going to be used.
1170 * @param selection A filter declaring which rows to return, formatted as an
1171 * SQL WHERE clause (excluding the WHERE itself). Passing null
1172 * will return all rows for the given table.
1173 * @param selectionArgs You may include ?s in selection, which will be
1174 * replaced by the values from selectionArgs, in order that they
1175 * appear in the selection. The values will be bound as Strings.
1176 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1177 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1178 * will cause the rows to not be grouped.
1179 * @param having A filter declare which row groups to include in the cursor,
1180 * if row grouping is being used, formatted as an SQL HAVING
1181 * clause (excluding the HAVING itself). Passing null will cause
1182 * all row groups to be included, and is required when row
1183 * grouping is not being used.
1184 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1185 * (excluding the ORDER BY itself). Passing null will use the
1186 * default sort order, which may be unordered.
1187 * @return A {@link Cursor} object, which is positioned before the first entry
1188 * @see Cursor
1189 */
1190 public Cursor query(String table, String[] columns, String selection,
1191 String[] selectionArgs, String groupBy, String having,
1192 String orderBy) {
1193
1194 return query(false, table, columns, selection, selectionArgs, groupBy,
1195 having, orderBy, null /* limit */);
1196 }
1197
1198 /**
1199 * Query the given table, returning a {@link Cursor} over the result set.
1200 *
1201 * @param table The table name to compile the query against.
1202 * @param columns A list of which columns to return. Passing null will
1203 * return all columns, which is discouraged to prevent reading
1204 * data from storage that isn't going to be used.
1205 * @param selection A filter declaring which rows to return, formatted as an
1206 * SQL WHERE clause (excluding the WHERE itself). Passing null
1207 * will return all rows for the given table.
1208 * @param selectionArgs You may include ?s in selection, which will be
1209 * replaced by the values from selectionArgs, in order that they
1210 * appear in the selection. The values will be bound as Strings.
1211 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1212 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1213 * will cause the rows to not be grouped.
1214 * @param having A filter declare which row groups to include in the cursor,
1215 * if row grouping is being used, formatted as an SQL HAVING
1216 * clause (excluding the HAVING itself). Passing null will cause
1217 * all row groups to be included, and is required when row
1218 * grouping is not being used.
1219 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1220 * (excluding the ORDER BY itself). Passing null will use the
1221 * default sort order, which may be unordered.
1222 * @param limit Limits the number of rows returned by the query,
1223 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1224 * @return A {@link Cursor} object, which is positioned before the first entry
1225 * @see Cursor
1226 */
1227 public Cursor query(String table, String[] columns, String selection,
1228 String[] selectionArgs, String groupBy, String having,
1229 String orderBy, String limit) {
1230
1231 return query(false, table, columns, selection, selectionArgs, groupBy,
1232 having, orderBy, limit);
1233 }
1234
1235 /**
1236 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1237 *
1238 * @param sql the SQL query. The SQL string must not be ; terminated
1239 * @param selectionArgs You may include ?s in where clause in the query,
1240 * which will be replaced by the values from selectionArgs. The
1241 * values will be bound as Strings.
1242 * @return A {@link Cursor} object, which is positioned before the first entry
1243 */
1244 public Cursor rawQuery(String sql, String[] selectionArgs) {
1245 return rawQueryWithFactory(null, sql, selectionArgs, null);
1246 }
1247
1248 /**
1249 * Runs the provided SQL and returns a cursor over the result set.
1250 *
1251 * @param cursorFactory the cursor factory to use, or null for the default factory
1252 * @param sql the SQL query. The SQL string must not be ; terminated
1253 * @param selectionArgs You may include ?s in where clause in the query,
1254 * which will be replaced by the values from selectionArgs. The
1255 * values will be bound as Strings.
1256 * @param editTable the name of the first table, which is editable
1257 * @return A {@link Cursor} object, which is positioned before the first entry
1258 */
1259 public Cursor rawQueryWithFactory(
1260 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1261 String editTable) {
1262 long timeStart = 0;
1263
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001264 if (Config.LOGV || mSlowQueryThreshold != -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 timeStart = System.currentTimeMillis();
1266 }
1267
1268 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
1269
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001270 Cursor cursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 try {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001272 cursor = driver.query(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 cursorFactory != null ? cursorFactory : mFactory,
1274 selectionArgs);
1275 } finally {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001276 if (Config.LOGV || mSlowQueryThreshold != -1) {
1277
1278 // Force query execution
1279 if (cursor != null) {
1280 cursor.moveToFirst();
1281 cursor.moveToPosition(-1);
1282 }
1283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 long duration = System.currentTimeMillis() - timeStart;
1285
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001286 if (Config.LOGV || duration >= mSlowQueryThreshold) {
1287 Log.v(SQLiteCursor.TAG,
1288 "query (" + duration + " ms): " + driver.toString() + ", args are "
1289 + (selectionArgs != null
1290 ? TextUtils.join(",", selectionArgs)
1291 : "<null>"));
1292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
1294 }
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001295 return cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 }
1297
1298 /**
1299 * Runs the provided SQL and returns a cursor over the result set.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001300 * The cursor will read an initial set of rows and the return to the caller.
1301 * It will continue to read in batches and send data changed notifications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 * when the later batches are ready.
1303 * @param sql the SQL query. The SQL string must not be ; terminated
1304 * @param selectionArgs You may include ?s in where clause in the query,
1305 * which will be replaced by the values from selectionArgs. The
1306 * values will be bound as Strings.
1307 * @param initialRead set the initial count of items to read from the cursor
1308 * @param maxRead set the count of items to read on each iteration after the first
1309 * @return A {@link Cursor} object, which is positioned before the first entry
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001310 *
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001311 * This work is incomplete and not fully tested or reviewed, so currently
1312 * hidden.
1313 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001315 public Cursor rawQuery(String sql, String[] selectionArgs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 int initialRead, int maxRead) {
1317 SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1318 null, sql, selectionArgs, null);
1319 c.setLoadStyle(initialRead, maxRead);
1320 return c;
1321 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 /**
1324 * Convenience method for inserting a row into the database.
1325 *
1326 * @param table the table to insert the row into
1327 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1328 * so if initialValues is empty this column will explicitly be
1329 * assigned a NULL value
1330 * @param values this map contains the initial column values for the
1331 * row. The keys should be the column names and the values the
1332 * column values
1333 * @return the row ID of the newly inserted row, or -1 if an error occurred
1334 */
1335 public long insert(String table, String nullColumnHack, ContentValues values) {
1336 try {
Vasu Nori6eb7c452010-01-27 14:31:24 -08001337 return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 } catch (SQLException e) {
1339 Log.e(TAG, "Error inserting " + values, e);
1340 return -1;
1341 }
1342 }
1343
1344 /**
1345 * Convenience method for inserting a row into the database.
1346 *
1347 * @param table the table to insert the row into
1348 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1349 * so if initialValues is empty this column will explicitly be
1350 * assigned a NULL value
1351 * @param values this map contains the initial column values for the
1352 * row. The keys should be the column names and the values the
1353 * column values
1354 * @throws SQLException
1355 * @return the row ID of the newly inserted row, or -1 if an error occurred
1356 */
1357 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1358 throws SQLException {
Vasu Nori6eb7c452010-01-27 14:31:24 -08001359 return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 }
1361
1362 /**
1363 * Convenience method for replacing a row in the database.
1364 *
1365 * @param table the table in which to replace the row
1366 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1367 * so if initialValues is empty this row will explicitly be
1368 * assigned a NULL value
1369 * @param initialValues this map contains the initial column values for
1370 * the row. The key
1371 * @return the row ID of the newly inserted row, or -1 if an error occurred
1372 */
1373 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1374 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001375 return insertWithOnConflict(table, nullColumnHack, initialValues,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 ConflictAlgorithm.REPLACE);
1377 } catch (SQLException e) {
1378 Log.e(TAG, "Error inserting " + initialValues, e);
1379 return -1;
1380 }
1381 }
1382
1383 /**
1384 * Convenience method for replacing a row in the database.
1385 *
1386 * @param table the table in which to replace the row
1387 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1388 * so if initialValues is empty this row will explicitly be
1389 * assigned a NULL value
1390 * @param initialValues this map contains the initial column values for
1391 * the row. The key
1392 * @throws SQLException
1393 * @return the row ID of the newly inserted row, or -1 if an error occurred
1394 */
1395 public long replaceOrThrow(String table, String nullColumnHack,
1396 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001397 return insertWithOnConflict(table, nullColumnHack, initialValues,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 ConflictAlgorithm.REPLACE);
1399 }
1400
1401 /**
1402 * General method for inserting a row into the database.
1403 *
1404 * @param table the table to insert the row into
1405 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1406 * so if initialValues is empty this column will explicitly be
1407 * assigned a NULL value
1408 * @param initialValues this map contains the initial column values for the
1409 * row. The keys should be the column names and the values the
1410 * column values
Vasu Nori6eb7c452010-01-27 14:31:24 -08001411 * @param conflictAlgorithm {@link ConflictAlgorithm} for insert conflict resolver
1412 * @return the row ID of the newly inserted row
1413 * OR the primary key of the existing row if the input param 'conflictAlgorithm' =
1414 * {@link ConflictAlgorithm#IGNORE}
1415 * OR -1 if any error
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 */
1417 public long insertWithOnConflict(String table, String nullColumnHack,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001418 ContentValues initialValues, int conflictAlgorithm) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 if (!isOpen()) {
1420 throw new IllegalStateException("database not open");
1421 }
1422
1423 // Measurements show most sql lengths <= 152
1424 StringBuilder sql = new StringBuilder(152);
1425 sql.append("INSERT");
Vasu Nori6eb7c452010-01-27 14:31:24 -08001426 sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 sql.append(" INTO ");
1428 sql.append(table);
1429 // Measurements show most values lengths < 40
1430 StringBuilder values = new StringBuilder(40);
1431
1432 Set<Map.Entry<String, Object>> entrySet = null;
1433 if (initialValues != null && initialValues.size() > 0) {
1434 entrySet = initialValues.valueSet();
1435 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1436 sql.append('(');
1437
1438 boolean needSeparator = false;
1439 while (entriesIter.hasNext()) {
1440 if (needSeparator) {
1441 sql.append(", ");
1442 values.append(", ");
1443 }
1444 needSeparator = true;
1445 Map.Entry<String, Object> entry = entriesIter.next();
1446 sql.append(entry.getKey());
1447 values.append('?');
1448 }
1449
1450 sql.append(')');
1451 } else {
1452 sql.append("(" + nullColumnHack + ") ");
1453 values.append("NULL");
1454 }
1455
1456 sql.append(" VALUES(");
1457 sql.append(values);
1458 sql.append(");");
1459
1460 lock();
1461 SQLiteStatement statement = null;
1462 try {
1463 statement = compileStatement(sql.toString());
1464
1465 // Bind the values
1466 if (entrySet != null) {
1467 int size = entrySet.size();
1468 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1469 for (int i = 0; i < size; i++) {
1470 Map.Entry<String, Object> entry = entriesIter.next();
1471 DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1472 }
1473 }
1474
1475 // Run the program and then cleanup
1476 statement.execute();
1477
1478 long insertedRowId = lastInsertRow();
1479 if (insertedRowId == -1) {
1480 Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1481 } else {
1482 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1483 Log.v(TAG, "Inserting row " + insertedRowId + " from "
1484 + initialValues + " using " + sql);
1485 }
1486 }
1487 return insertedRowId;
1488 } catch (SQLiteDatabaseCorruptException e) {
1489 onCorruption();
1490 throw e;
1491 } finally {
1492 if (statement != null) {
1493 statement.close();
1494 }
1495 unlock();
1496 }
1497 }
1498
1499 /**
1500 * Convenience method for deleting rows in the database.
1501 *
1502 * @param table the table to delete from
1503 * @param whereClause the optional WHERE clause to apply when deleting.
1504 * Passing null will delete all rows.
1505 * @return the number of rows affected if a whereClause is passed in, 0
1506 * otherwise. To remove all rows and get a count pass "1" as the
1507 * whereClause.
1508 */
1509 public int delete(String table, String whereClause, String[] whereArgs) {
1510 if (!isOpen()) {
1511 throw new IllegalStateException("database not open");
1512 }
1513 lock();
1514 SQLiteStatement statement = null;
1515 try {
1516 statement = compileStatement("DELETE FROM " + table
1517 + (!TextUtils.isEmpty(whereClause)
1518 ? " WHERE " + whereClause : ""));
1519 if (whereArgs != null) {
1520 int numArgs = whereArgs.length;
1521 for (int i = 0; i < numArgs; i++) {
1522 DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1523 }
1524 }
1525 statement.execute();
1526 statement.close();
1527 return lastChangeCount();
1528 } catch (SQLiteDatabaseCorruptException e) {
1529 onCorruption();
1530 throw e;
1531 } finally {
1532 if (statement != null) {
1533 statement.close();
1534 }
1535 unlock();
1536 }
1537 }
1538
1539 /**
1540 * Convenience method for updating rows in the database.
1541 *
1542 * @param table the table to update in
1543 * @param values a map from column names to new column values. null is a
1544 * valid value that will be translated to NULL.
1545 * @param whereClause the optional WHERE clause to apply when updating.
1546 * Passing null will update all rows.
1547 * @return the number of rows affected
1548 */
1549 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
Vasu Nori6eb7c452010-01-27 14:31:24 -08001550 return updateWithOnConflict(table, values, whereClause, whereArgs, ConflictAlgorithm.NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 /**
1554 * Convenience method for updating rows in the database.
1555 *
1556 * @param table the table to update in
1557 * @param values a map from column names to new column values. null is a
1558 * valid value that will be translated to NULL.
1559 * @param whereClause the optional WHERE clause to apply when updating.
1560 * Passing null will update all rows.
Vasu Nori6eb7c452010-01-27 14:31:24 -08001561 * @param conflictAlgorithm {@link ConflictAlgorithm} for update conflict resolver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 * @return the number of rows affected
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001564 public int updateWithOnConflict(String table, ContentValues values,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001565 String whereClause, String[] whereArgs, int conflictAlgorithm) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 if (!isOpen()) {
1567 throw new IllegalStateException("database not open");
1568 }
1569
1570 if (values == null || values.size() == 0) {
1571 throw new IllegalArgumentException("Empty values");
1572 }
1573
1574 StringBuilder sql = new StringBuilder(120);
1575 sql.append("UPDATE ");
Vasu Nori6eb7c452010-01-27 14:31:24 -08001576 sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 sql.append(table);
1578 sql.append(" SET ");
1579
1580 Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1581 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1582
1583 while (entriesIter.hasNext()) {
1584 Map.Entry<String, Object> entry = entriesIter.next();
1585 sql.append(entry.getKey());
1586 sql.append("=?");
1587 if (entriesIter.hasNext()) {
1588 sql.append(", ");
1589 }
1590 }
1591
1592 if (!TextUtils.isEmpty(whereClause)) {
1593 sql.append(" WHERE ");
1594 sql.append(whereClause);
1595 }
1596
1597 lock();
1598 SQLiteStatement statement = null;
1599 try {
1600 statement = compileStatement(sql.toString());
1601
1602 // Bind the values
1603 int size = entrySet.size();
1604 entriesIter = entrySet.iterator();
1605 int bindArg = 1;
1606 for (int i = 0; i < size; i++) {
1607 Map.Entry<String, Object> entry = entriesIter.next();
1608 DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1609 bindArg++;
1610 }
1611
1612 if (whereArgs != null) {
1613 size = whereArgs.length;
1614 for (int i = 0; i < size; i++) {
1615 statement.bindString(bindArg, whereArgs[i]);
1616 bindArg++;
1617 }
1618 }
1619
1620 // Run the program and then cleanup
1621 statement.execute();
1622 statement.close();
1623 int numChangedRows = lastChangeCount();
1624 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1625 Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1626 }
1627 return numChangedRows;
1628 } catch (SQLiteDatabaseCorruptException e) {
1629 onCorruption();
1630 throw e;
1631 } catch (SQLException e) {
1632 Log.e(TAG, "Error updating " + values + " using " + sql);
1633 throw e;
1634 } finally {
1635 if (statement != null) {
1636 statement.close();
1637 }
1638 unlock();
1639 }
1640 }
1641
1642 /**
1643 * Execute a single SQL statement that is not a query. For example, CREATE
1644 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1645 * supported. it takes a write lock
1646 *
1647 * @throws SQLException If the SQL string is invalid for some reason
1648 */
1649 public void execSQL(String sql) throws SQLException {
Dan Egnor12311952009-11-23 14:47:45 -08001650 long timeStart = Debug.threadCpuTimeNanos();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 lock();
1652 try {
1653 native_execSQL(sql);
1654 } catch (SQLiteDatabaseCorruptException e) {
1655 onCorruption();
1656 throw e;
1657 } finally {
1658 unlock();
1659 }
Dan Egnor12311952009-11-23 14:47:45 -08001660 logTimeStat(sql, timeStart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
1662
1663 /**
1664 * Execute a single SQL statement that is not a query. For example, CREATE
1665 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1666 * supported. it takes a write lock,
1667 *
1668 * @param sql
1669 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1670 * @throws SQLException If the SQL string is invalid for some reason
1671 */
1672 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1673 if (bindArgs == null) {
1674 throw new IllegalArgumentException("Empty bindArgs");
1675 }
1676
Dan Egnor12311952009-11-23 14:47:45 -08001677 long timeStart = Debug.threadCpuTimeNanos();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 lock();
1679 SQLiteStatement statement = null;
1680 try {
1681 statement = compileStatement(sql);
1682 if (bindArgs != null) {
1683 int numArgs = bindArgs.length;
1684 for (int i = 0; i < numArgs; i++) {
1685 DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1686 }
1687 }
1688 statement.execute();
1689 } catch (SQLiteDatabaseCorruptException e) {
1690 onCorruption();
1691 throw e;
1692 } finally {
1693 if (statement != null) {
1694 statement.close();
1695 }
1696 unlock();
1697 }
Dan Egnor12311952009-11-23 14:47:45 -08001698 logTimeStat(sql, timeStart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
1700
1701 @Override
1702 protected void finalize() {
1703 if (isOpen()) {
1704 if (mPrograms.isEmpty()) {
1705 Log.e(TAG, "Leak found", mLeakedException);
1706 } else {
1707 IllegalStateException leakProgram = new IllegalStateException(
1708 "mPrograms size " + mPrograms.size(), mLeakedException);
1709 Log.e(TAG, "Leak found", leakProgram);
1710 }
1711 closeClosable();
1712 onAllReferencesReleased();
1713 }
1714 }
1715
1716 /**
1717 * Private constructor. See {@link #create} and {@link #openDatabase}.
1718 *
1719 * @param path The full path to the database
1720 * @param factory The factory to use when creating cursors, may be NULL.
1721 * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
1722 * exists, mFlags will be updated appropriately.
1723 */
1724 private SQLiteDatabase(String path, CursorFactory factory, int flags) {
1725 if (path == null) {
1726 throw new IllegalArgumentException("path should not be null");
1727 }
1728 mFlags = flags;
1729 mPath = path;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001730 mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 mLeakedException = new IllegalStateException(path +
1733 " SQLiteDatabase created and never closed");
1734 mFactory = factory;
1735 dbopen(mPath, mFlags);
Vasu Nori5a03f362009-10-20 15:16:35 -07001736 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1737 mTimeOpened = getTime();
1738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 mPrograms = new WeakHashMap<SQLiteClosable,Object>();
1740 try {
1741 setLocale(Locale.getDefault());
1742 } catch (RuntimeException e) {
1743 Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
1744 dbclose();
Vasu Nori5a03f362009-10-20 15:16:35 -07001745 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1746 mTimeClosed = getTime();
1747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 throw e;
1749 }
1750 }
1751
Vasu Nori5a03f362009-10-20 15:16:35 -07001752 private String getTime() {
1753 return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
1754 }
1755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 /**
1757 * return whether the DB is opened as read only.
1758 * @return true if DB is opened as read only
1759 */
1760 public boolean isReadOnly() {
1761 return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1762 }
1763
1764 /**
1765 * @return true if the DB is currently open (has not been closed)
1766 */
1767 public boolean isOpen() {
1768 return mNativeHandle != 0;
1769 }
1770
1771 public boolean needUpgrade(int newVersion) {
1772 return newVersion > getVersion();
1773 }
1774
1775 /**
1776 * Getter for the path to the database file.
1777 *
1778 * @return the path to our database file.
1779 */
1780 public final String getPath() {
1781 return mPath;
1782 }
1783
Vasu Nori5a03f362009-10-20 15:16:35 -07001784
Vasu Nori5a03f362009-10-20 15:16:35 -07001785
Dan Egnor12311952009-11-23 14:47:45 -08001786 /* package */ void logTimeStat(String sql, long beginNanos) {
1787 // Sample fast queries in proportion to the time taken.
1788 // Quantize the % first, so the logged sampling probability
1789 // exactly equals the actual sampling rate for this query.
1790
1791 int samplePercent;
1792 long nanos = Debug.threadCpuTimeNanos() - beginNanos;
1793 if (nanos >= QUERY_LOG_TIME_IN_NANOS) {
1794 samplePercent = 100;
1795 } else {
1796 samplePercent = (int) (100 * nanos / QUERY_LOG_TIME_IN_NANOS) + 1;
Dan Egnor799f7212009-11-24 16:24:44 -08001797 if (mRandom.nextInt(100) >= samplePercent) return;
Dan Egnor12311952009-11-23 14:47:45 -08001798 }
1799
1800 if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
1801
1802 // ActivityThread.currentPackageName() only returns non-null if the
1803 // current thread is an application main thread. This parameter tells
1804 // us whether an event loop is blocked, and if so, which app it is.
1805 //
1806 // Sadly, there's no fast way to determine app name if this is *not* a
1807 // main thread, or when we are invoked via Binder (e.g. ContentProvider).
1808 // Hopefully the full path to the database will be informative enough.
1809
1810 String blockingPackage = ActivityThread.currentPackageName();
1811 if (blockingPackage == null) blockingPackage = "";
1812
1813 int millis = (int) (nanos / 1000000);
1814 EventLog.writeEvent(EVENT_DB_OPERATION, mPath, sql, millis, blockingPackage, samplePercent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816
1817 /**
1818 * Sets the locale for this database. Does nothing if this database has
1819 * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
1820 * @throws SQLException if the locale could not be set. The most common reason
1821 * for this is that there is no collator available for the locale you requested.
1822 * In this case the database remains unchanged.
1823 */
1824 public void setLocale(Locale locale) {
1825 lock();
1826 try {
1827 native_setLocale(locale.toString(), mFlags);
1828 } finally {
1829 unlock();
1830 }
1831 }
1832
Vasu Norie495d1f2010-01-06 16:34:19 -08001833 /*
1834 * ============================================================================
1835 *
1836 * The following methods deal with compiled-sql cache
1837 * ============================================================================
1838 */
1839 /**
1840 * adds the given sql and its compiled-statement-id-returned-by-sqlite to the
1841 * cache of compiledQueries attached to 'this'.
1842 *
1843 * if there is already a {@link SQLiteCompiledSql} in compiledQueries for the given sql,
1844 * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
1845 * mapping is NOT replaced with the new mapping).
1846 */
1847 /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
1848 if (mMaxSqlCacheSize == 0) {
1849 // for this database, there is no cache of compiled sql.
1850 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1851 Log.v(TAG, "|NOT adding_sql_to_cache|" + getPath() + "|" + sql);
1852 }
1853 return;
1854 }
1855
Vasu Nori994bc222010-01-20 16:36:28 -08001856 /* don't cache PRAGMA sql statements.
1857 * caching them makes sqlite return incorrect results on pragma sql execution!
1858 */
1859 String prefixSql = sql.substring(0, 6);
1860 if (prefixSql.toLowerCase().startsWith("pragma")) {
1861 return;
1862 }
1863
Vasu Norie495d1f2010-01-06 16:34:19 -08001864 SQLiteCompiledSql compiledSql = null;
1865 synchronized(mCompiledQueries) {
1866 // don't insert the new mapping if a mapping already exists
1867 compiledSql = mCompiledQueries.get(sql);
1868 if (compiledSql != null) {
1869 return;
1870 }
1871 // add this <sql, compiledStatement> to the cache
1872 if (mCompiledQueries.size() == mMaxSqlCacheSize) {
1873 /* reached max cachesize. before adding new entry, remove an entry from the
1874 * cache. we don't want to wipe out the entire cache because of this:
1875 * GCing {@link SQLiteCompiledSql} requires call to sqlite3_finalize
1876 * JNI method. If entire cache is wiped out, it could cause a big GC activity
1877 * just because a (rogue) process is using the cache incorrectly.
1878 */
Vasu Norie9d92102010-01-20 15:07:26 -08001879 Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
1880 getPath() + "; i.e., NO space for this sql statement in cache: " +
1881 sql + ". Make sure your sql " +
Vasu Noribee5b9d2010-01-15 10:44:57 -08001882 "statements are using prepared-sql-statement syntax with '?' for " +
Vasu Norie495d1f2010-01-06 16:34:19 -08001883 "bindargs, instead of using actual values");
Vasu Norie9d92102010-01-20 15:07:26 -08001884
1885 /* increment the number of times this warnings has been printed.
1886 * if this warning is printed too many times, clear the whole cache - the app
1887 * is doing something weird or incorrect and printing more warnings will only
1888 * flood the logfile.
1889 */
1890 if (++mCacheFullWarnings > MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
1891 mCacheFullWarnings = 0;
1892 // clear the cache
1893 mCompiledQueries.clear();
1894 Log.w(TAG, "compiled-sql statement cache cleared for the database " +
1895 getPath());
1896 } else {
1897 // clear just a single entry from cache
1898 Set<String> keySet = mCompiledQueries.keySet();
1899 for (String s : keySet) {
1900 mCompiledQueries.remove(s);
1901 break;
1902 }
Vasu Norie495d1f2010-01-06 16:34:19 -08001903 }
1904 }
1905 mCompiledQueries.put(sql, compiledStatement);
1906 }
1907 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1908 Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" + mCompiledQueries.size() + "|" +
1909 sql);
1910 }
1911 return;
1912 }
1913
1914
1915 private void deallocCachedSqlStatements() {
1916 synchronized (mCompiledQueries) {
1917 for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
1918 compiledSql.releaseSqlStatement();
1919 }
1920 mCompiledQueries.clear();
1921 }
1922 }
1923
1924 /**
1925 * from the compiledQueries cache, returns the compiled-statement-id for the given sql.
1926 * returns null, if not found in the cache.
1927 */
1928 /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
Vasu Nori994bc222010-01-20 16:36:28 -08001929 // don't look for PRAGMA sql statements in compiled-sql cache
1930 String prefixSql = sql.substring(0, 6);
1931 if (prefixSql.toLowerCase().startsWith("pragma")) {
1932 return null;
1933 }
1934
Vasu Norie495d1f2010-01-06 16:34:19 -08001935 SQLiteCompiledSql compiledStatement = null;
1936 boolean cacheHit;
1937 synchronized(mCompiledQueries) {
1938 if (mMaxSqlCacheSize == 0) {
1939 // for this database, there is no cache of compiled sql.
1940 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1941 Log.v(TAG, "|cache NOT found|" + getPath());
1942 }
1943 return null;
1944 }
1945 cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null;
1946 }
1947 if (cacheHit) {
1948 mNumCacheHits++;
1949 } else {
1950 mNumCacheMisses++;
1951 }
1952
1953 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1954 Log.v(TAG, "|cache_stats|" +
1955 getPath() + "|" + mCompiledQueries.size() +
1956 "|" + mNumCacheHits + "|" + mNumCacheMisses +
1957 "|" + cacheHit + "|" + mTimeOpened + "|" + mTimeClosed + "|" + sql);
1958 }
1959 return compiledStatement;
1960 }
1961
1962 /**
1963 * returns true if the given sql is cached in compiled-sql cache.
1964 * @hide
1965 */
1966 public boolean isInCompiledSqlCache(String sql) {
1967 synchronized(mCompiledQueries) {
1968 return mCompiledQueries.containsKey(sql);
1969 }
1970 }
1971
1972 /**
1973 * purges the given sql from the compiled-sql cache.
1974 * @hide
1975 */
1976 public void purgeFromCompiledSqlCache(String sql) {
1977 synchronized(mCompiledQueries) {
1978 mCompiledQueries.remove(sql);
1979 }
1980 }
1981
1982 /**
1983 * remove everything from the compiled sql cache
1984 * @hide
1985 */
1986 public void resetCompiledSqlCache() {
1987 synchronized(mCompiledQueries) {
1988 mCompiledQueries.clear();
1989 }
1990 }
1991
1992 /**
1993 * return the current maxCacheSqlCacheSize
1994 * @hide
1995 */
1996 public synchronized int getMaxSqlCacheSize() {
1997 return mMaxSqlCacheSize;
1998 }
1999
2000 /**
2001 * set the max size of the compiled sql cache for this database after purging the cache.
2002 * (size of the cache = number of compiled-sql-statements stored in the cache).
2003 *
2004 * max cache size can ONLY be increased from its current size (default = 0).
2005 * if this method is called with smaller size than the current value of mMaxSqlCacheSize,
2006 * then IllegalStateException is thrown
2007 *
2008 * synchronized because we don't want t threads to change cache size at the same time.
2009 * @param cacheSize the size of the cache. can be (0 to MAX_SQL_CACHE_SIZE)
2010 * @throws IllegalStateException if input cacheSize > MAX_SQL_CACHE_SIZE or < 0 or
2011 * < the value set with previous setMaxSqlCacheSize() call.
2012 *
2013 * @hide
2014 */
2015 public synchronized void setMaxSqlCacheSize(int cacheSize) {
2016 if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
2017 throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE);
2018 } else if (cacheSize < mMaxSqlCacheSize) {
2019 throw new IllegalStateException("cannot set cacheSize to a value less than the value " +
2020 "set with previous setMaxSqlCacheSize() call.");
2021 }
2022 mMaxSqlCacheSize = cacheSize;
2023 }
2024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 /**
2026 * Native call to open the database.
2027 *
2028 * @param path The full path to the database
2029 */
2030 private native void dbopen(String path, int flags);
2031
2032 /**
2033 * Native call to execute a raw SQL statement. {@link #lock} must be held
2034 * when calling this method.
2035 *
2036 * @param sql The raw SQL string
2037 * @throws SQLException
2038 */
2039 /* package */ native void native_execSQL(String sql) throws SQLException;
2040
2041 /**
2042 * Native call to set the locale. {@link #lock} must be held when calling
2043 * this method.
2044 * @throws SQLException
2045 */
2046 /* package */ native void native_setLocale(String loc, int flags);
2047
2048 /**
2049 * Returns the row ID of the last row inserted into the database.
2050 *
2051 * @return the row ID of the last row inserted into the database.
2052 */
2053 /* package */ native long lastInsertRow();
2054
2055 /**
2056 * Returns the number of changes made in the last statement executed.
2057 *
2058 * @return the number of changes made in the last statement executed.
2059 */
2060 /* package */ native int lastChangeCount();
2061}