blob: 4f31ef098206cc3bf5b2b65104e8dc473868b965 [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
19import android.content.ContentValues;
20import android.database.Cursor;
21import android.database.DatabaseUtils;
22import android.database.SQLException;
23import android.os.Debug;
24import android.os.SystemClock;
25import android.text.TextUtils;
26import android.util.Config;
27import android.util.Log;
28import android.util.EventLog;
29
30import java.io.File;
31import java.util.HashMap;
32import java.util.Iterator;
33import java.util.Locale;
34import java.util.Map;
35import java.util.Set;
36import java.util.WeakHashMap;
37import java.util.concurrent.locks.ReentrantLock;
38
39/**
40 * Exposes methods to manage a SQLite database.
41 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
42 * perform other common database management tasks.
43 * <p>See the Notepad sample application in the SDK for an example of creating
44 * and managing a database.
45 * <p> Database names must be unique within an application, not across all
46 * applications.
47 *
48 * <h3>Localized Collation - ORDER BY</h3>
49 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
50 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
51 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
52 * is the Unicode Collation Algorithm and not tailored to the current locale.
53 */
54public class SQLiteDatabase extends SQLiteClosable {
55 private static final String TAG = "Database";
56 private static final int DB_OPERATION_EVENT = 52000;
57
58 /**
59 * Algorithms used in ON CONFLICT clause
60 * http://www.sqlite.org/lang_conflict.html
61 * @hide
62 */
63 public enum ConflictAlgorithm {
64 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070065 * When a constraint violation occurs, an immediate ROLLBACK occurs,
66 * thus ending the current transaction, and the command aborts with a
67 * return code of SQLITE_CONSTRAINT. If no transaction is active
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 * (other than the implied transaction that is created on every command)
69 * then this algorithm works the same as ABORT.
70 */
71 ROLLBACK("ROLLBACK"),
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070074 * When a constraint violation occurs,no ROLLBACK is executed
75 * so changes from prior commands within the same transaction
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 * are preserved. This is the default behavior.
77 */
78 ABORT("ABORT"),
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070081 * When a constraint violation occurs, the command aborts with a return
82 * code SQLITE_CONSTRAINT. But any changes to the database that
83 * the command made prior to encountering the constraint violation
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 * are preserved and are not backed out.
85 */
86 FAIL("FAIL"),
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 /**
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070089 * When a constraint violation occurs, the one row that contains
90 * the constraint violation is not inserted or changed.
91 * But the command continues executing normally. Other rows before and
92 * after the row that contained the constraint violation continue to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 * inserted or updated normally. No error is returned.
94 */
95 IGNORE("IGNORE"),
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 /**
98 * When a UNIQUE constraint violation occurs, the pre-existing rows that
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070099 * are causing the constraint violation are removed prior to inserting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 * or updating the current row. Thus the insert or update always occurs.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700101 * The command continues executing normally. No error is returned.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 * If a NOT NULL constraint violation occurs, the NULL value is replaced
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700103 * by the default value for that column. If the column has no default
104 * value, then the ABORT algorithm is used. If a CHECK constraint
105 * violation occurs then the IGNORE algorithm is used. When this conflict
106 * resolution strategy deletes rows in order to satisfy a constraint,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 * it does not invoke delete triggers on those rows.
108 * This behavior might change in a future release.
109 */
110 REPLACE("REPLACE");
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private final String mValue;
113 ConflictAlgorithm(String value) {
114 mValue = value;
115 }
116 public String value() {
117 return mValue;
118 }
119 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /**
122 * Maximum Length Of A LIKE Or GLOB Pattern
123 * The pattern matching algorithm used in the default LIKE and GLOB implementation
124 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
125 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
126 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
127 * The default value of this limit is 50000. A modern workstation can evaluate
128 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
129 * The denial of service problem only comes into play when the pattern length gets
130 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
131 * are at most a few dozen bytes in length, paranoid application developers may
132 * want to reduce this parameter to something in the range of a few hundred
133 * if they know that external users are able to generate arbitrary patterns.
134 */
135 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
136
137 /**
138 * Flag for {@link #openDatabase} to open the database for reading and writing.
139 * If the disk is full, this may fail even before you actually write anything.
140 *
141 * {@more} Note that the value of this flag is 0, so it is the default.
142 */
143 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
144
145 /**
146 * Flag for {@link #openDatabase} to open the database for reading only.
147 * This is the only reliable way to open a database if the disk may be full.
148 */
149 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
150
151 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
152
153 /**
154 * Flag for {@link #openDatabase} to open the database without support for localized collators.
155 *
156 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
157 * You must be consistent when using this flag to use the setting the database was
158 * created with. If this is set, {@link #setLocale} will do nothing.
159 */
160 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
161
162 /**
163 * Flag for {@link #openDatabase} to create the database file if it does not already exist.
164 */
165 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
166
167 /**
168 * Indicates whether the most-recently started transaction has been marked as successful.
169 */
170 private boolean mInnerTransactionIsSuccessful;
171
172 /**
173 * Valid during the life of a transaction, and indicates whether the entire transaction (the
174 * outer one and all of the inner ones) so far has been successful.
175 */
176 private boolean mTransactionIsSuccessful;
177
Fred Quintanac4516a72009-09-03 12:14:06 -0700178 /**
179 * Valid during the life of a transaction.
180 */
181 private SQLiteTransactionListener mTransactionListener;
182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 /** Synchronize on this when accessing the database */
184 private final ReentrantLock mLock = new ReentrantLock(true);
185
186 private long mLockAcquiredWallTime = 0L;
187 private long mLockAcquiredThreadTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 // limit the frequency of complaints about each database to one within 20 sec
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700190 // unless run command adb shell setprop log.tag.Database VERBOSE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
192 /** If the lock is held this long then a warning will be printed when it is released. */
193 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
194 private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
195 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
196
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700197 private static final int SLEEP_AFTER_YIELD_QUANTUM = 500;
198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private long mLastLockMessageTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 /** Used by native code, do not rename */
202 /* package */ int mNativeHandle = 0;
203
204 /** Used to make temp table names unique */
205 /* package */ int mTempTableSequence = 0;
206
207 /** The path for the database file */
208 private String mPath;
209
210 /** The flags passed to open/create */
211 private int mFlags;
212
213 /** The optional factory to use when creating new Cursors */
214 private CursorFactory mFactory;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 private WeakHashMap<SQLiteClosable, Object> mPrograms;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private final RuntimeException mLeakedException;
219
220 // package visible, since callers will access directly to minimize overhead in the case
221 // that logging is not enabled.
222 /* package */ final boolean mLogStats;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 /**
225 * @param closable
226 */
227 void addSQLiteClosable(SQLiteClosable closable) {
228 lock();
229 try {
230 mPrograms.put(closable, null);
231 } finally {
232 unlock();
233 }
234 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 void removeSQLiteClosable(SQLiteClosable closable) {
237 lock();
238 try {
239 mPrograms.remove(closable);
240 } finally {
241 unlock();
242 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700243 }
244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 @Override
246 protected void onAllReferencesReleased() {
247 if (isOpen()) {
248 dbclose();
249 }
250 }
251
252 /**
253 * Attempts to release memory that SQLite holds but does not require to
254 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700255 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 * @return the number of bytes actually released
257 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700258 static public native int releaseMemory();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 /**
261 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
262 * around critical sections. This is pretty expensive, so if you know that your
263 * DB will only be used by a single thread then you should set this to false.
264 * The default is true.
265 * @param lockingEnabled set to true to enable locks, false otherwise
266 */
267 public void setLockingEnabled(boolean lockingEnabled) {
268 mLockingEnabled = lockingEnabled;
269 }
270
271 /**
272 * If set then the SQLiteDatabase is made thread-safe by using locks
273 * around critical sections
274 */
275 private boolean mLockingEnabled = true;
276
277 /* package */ void onCorruption() {
278 try {
279 // Close the database (if we can), which will cause subsequent operations to fail.
280 close();
281 } finally {
282 Log.e(TAG, "Removing corrupt database: " + mPath);
283 // Delete the corrupt file. Don't re-create it now -- that would just confuse people
284 // -- but the next time someone tries to open it, they can set it up from scratch.
285 new File(mPath).delete();
286 }
287 }
288
289 /**
290 * Locks the database for exclusive access. The database lock must be held when
291 * touch the native sqlite3* object since it is single threaded and uses
292 * a polling lock contention algorithm. The lock is recursive, and may be acquired
293 * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700294 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 * @see #unlock()
296 */
297 /* package */ void lock() {
298 if (!mLockingEnabled) return;
299 mLock.lock();
300 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
301 if (mLock.getHoldCount() == 1) {
302 // Use elapsed real-time since the CPU may sleep when waiting for IO
303 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
304 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
305 }
306 }
307 }
308
309 /**
310 * Locks the database for exclusive access. The database lock must be held when
311 * touch the native sqlite3* object since it is single threaded and uses
312 * a polling lock contention algorithm. The lock is recursive, and may be acquired
313 * multiple times by the same thread.
314 *
315 * @see #unlockForced()
316 */
317 private void lockForced() {
318 mLock.lock();
319 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
320 if (mLock.getHoldCount() == 1) {
321 // Use elapsed real-time since the CPU may sleep when waiting for IO
322 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
323 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
324 }
325 }
326 }
327
328 /**
329 * Releases the database lock. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700330 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 * @see #unlock()
332 */
333 /* package */ void unlock() {
334 if (!mLockingEnabled) return;
335 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
336 if (mLock.getHoldCount() == 1) {
337 checkLockHoldTime();
338 }
339 }
340 mLock.unlock();
341 }
342
343 /**
344 * Releases the database lock.
345 *
346 * @see #unlockForced()
347 */
348 private void unlockForced() {
349 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
350 if (mLock.getHoldCount() == 1) {
351 checkLockHoldTime();
352 }
353 }
354 mLock.unlock();
355 }
356
357 private void checkLockHoldTime() {
358 // Use elapsed real-time since the CPU may sleep when waiting for IO
359 long elapsedTime = SystemClock.elapsedRealtime();
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700360 long lockedTime = elapsedTime - mLockAcquiredWallTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
362 !Log.isLoggable(TAG, Log.VERBOSE) &&
363 (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
364 return;
365 }
366 if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
367 int threadTime = (int)
368 ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
369 if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
370 lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
371 mLastLockMessageTime = elapsedTime;
372 String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
373 + threadTime + "ms";
374 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
375 Log.d(TAG, msg, new Exception());
376 } else {
377 Log.d(TAG, msg);
378 }
379 }
380 }
381 }
382
383 /**
384 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
385 * the work done in that transaction and all of the nested transactions will be committed or
386 * rolled back. The changes will be rolled back if any transaction is ended without being
387 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
388 *
389 * <p>Here is the standard idiom for transactions:
390 *
391 * <pre>
392 * db.beginTransaction();
393 * try {
394 * ...
395 * db.setTransactionSuccessful();
396 * } finally {
397 * db.endTransaction();
398 * }
399 * </pre>
400 */
401 public void beginTransaction() {
Fred Quintanac4516a72009-09-03 12:14:06 -0700402 beginTransactionWithListener(null /* transactionStatusCallback */);
403 }
404
405 /**
406 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
407 * the work done in that transaction and all of the nested transactions will be committed or
408 * rolled back. The changes will be rolled back if any transaction is ended without being
409 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
410 *
411 * <p>Here is the standard idiom for transactions:
412 *
413 * <pre>
414 * db.beginTransactionWithListener(listener);
415 * try {
416 * ...
417 * db.setTransactionSuccessful();
418 * } finally {
419 * db.endTransaction();
420 * }
421 * </pre>
422 * @param transactionListener listener that should be notified when the transaction begins,
423 * commits, or is rolled back, either explicitly or by a call to
424 * {@link #yieldIfContendedSafely}.
425 */
426 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 lockForced();
428 boolean ok = false;
429 try {
430 // If this thread already had the lock then get out
431 if (mLock.getHoldCount() > 1) {
432 if (mInnerTransactionIsSuccessful) {
433 String msg = "Cannot call beginTransaction between "
434 + "calling setTransactionSuccessful and endTransaction";
435 IllegalStateException e = new IllegalStateException(msg);
436 Log.e(TAG, "beginTransaction() failed", e);
437 throw e;
438 }
439 ok = true;
440 return;
441 }
442
443 // This thread didn't already have the lock, so begin a database
444 // transaction now.
445 execSQL("BEGIN EXCLUSIVE;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700446 mTransactionListener = transactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 mTransactionIsSuccessful = true;
448 mInnerTransactionIsSuccessful = false;
Fred Quintanac4516a72009-09-03 12:14:06 -0700449 if (transactionListener != null) {
450 try {
451 transactionListener.onBegin();
452 } catch (RuntimeException e) {
453 execSQL("ROLLBACK;");
454 throw e;
455 }
456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 ok = true;
458 } finally {
459 if (!ok) {
460 // beginTransaction is called before the try block so we must release the lock in
461 // the case of failure.
462 unlockForced();
463 }
464 }
465 }
466
467 /**
468 * End a transaction. See beginTransaction for notes about how to use this and when transactions
469 * are committed and rolled back.
470 */
471 public void endTransaction() {
472 if (!mLock.isHeldByCurrentThread()) {
473 throw new IllegalStateException("no transaction pending");
474 }
475 try {
476 if (mInnerTransactionIsSuccessful) {
477 mInnerTransactionIsSuccessful = false;
478 } else {
479 mTransactionIsSuccessful = false;
480 }
481 if (mLock.getHoldCount() != 1) {
482 return;
483 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700484 RuntimeException savedException = null;
485 if (mTransactionListener != null) {
486 try {
487 if (mTransactionIsSuccessful) {
488 mTransactionListener.onCommit();
489 } else {
490 mTransactionListener.onRollback();
491 }
492 } catch (RuntimeException e) {
493 savedException = e;
494 mTransactionIsSuccessful = false;
495 }
496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 if (mTransactionIsSuccessful) {
498 execSQL("COMMIT;");
499 } else {
500 try {
501 execSQL("ROLLBACK;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700502 if (savedException != null) {
503 throw savedException;
504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 } catch (SQLException e) {
506 if (Config.LOGD) {
507 Log.d(TAG, "exception during rollback, maybe the DB previously "
508 + "performed an auto-rollback");
509 }
510 }
511 }
512 } finally {
Fred Quintanac4516a72009-09-03 12:14:06 -0700513 mTransactionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 unlockForced();
515 if (Config.LOGV) {
516 Log.v(TAG, "unlocked " + Thread.currentThread()
517 + ", holdCount is " + mLock.getHoldCount());
518 }
519 }
520 }
521
522 /**
523 * Marks the current transaction as successful. Do not do any more database work between
524 * calling this and calling endTransaction. Do as little non-database work as possible in that
525 * situation too. If any errors are encountered between this and endTransaction the transaction
526 * will still be committed.
527 *
528 * @throws IllegalStateException if the current thread is not in a transaction or the
529 * transaction is already marked as successful.
530 */
531 public void setTransactionSuccessful() {
532 if (!mLock.isHeldByCurrentThread()) {
533 throw new IllegalStateException("no transaction pending");
534 }
535 if (mInnerTransactionIsSuccessful) {
536 throw new IllegalStateException(
537 "setTransactionSuccessful may only be called once per call to beginTransaction");
538 }
539 mInnerTransactionIsSuccessful = true;
540 }
541
542 /**
543 * return true if there is a transaction pending
544 */
545 public boolean inTransaction() {
546 return mLock.getHoldCount() > 0;
547 }
548
549 /**
550 * Checks if the database lock is held by this thread.
551 *
552 * @return true, if this thread is holding the database lock.
553 */
554 public boolean isDbLockedByCurrentThread() {
555 return mLock.isHeldByCurrentThread();
556 }
557
558 /**
559 * Checks if the database is locked by another thread. This is
560 * just an estimate, since this status can change at any time,
561 * including after the call is made but before the result has
562 * been acted upon.
563 *
564 * @return true, if the database is locked by another thread
565 */
566 public boolean isDbLockedByOtherThreads() {
567 return !mLock.isHeldByCurrentThread() && mLock.isLocked();
568 }
569
570 /**
571 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
572 * successful so far. Do not call setTransactionSuccessful before calling this. When this
573 * returns a new transaction will have been created but not marked as successful.
574 * @return true if the transaction was yielded
575 * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
576 * will not be yielded. Use yieldIfContendedSafely instead.
577 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700578 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700580 return yieldIfContendedHelper(false /* do not check yielding */,
581 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583
584 /**
585 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
586 * successful so far. Do not call setTransactionSuccessful before calling this. When this
587 * returns a new transaction will have been created but not marked as successful. This assumes
588 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700589 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 * @return true if the transaction was yielded
591 */
592 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700593 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595
Fred Quintana5c7aede2009-08-27 21:41:27 -0700596 /**
597 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
598 * successful so far. Do not call setTransactionSuccessful before calling this. When this
599 * returns a new transaction will have been created but not marked as successful. This assumes
600 * that there are no nested transactions (beginTransaction has only been called once) and will
601 * throw an exception if that is not the case.
602 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
603 * the lock was actually yielded. This will allow other background threads to make some
604 * more progress than they would if we started the transaction immediately.
605 * @return true if the transaction was yielded
606 */
607 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
608 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
609 }
610
611 private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 if (mLock.getQueueLength() == 0) {
613 // Reset the lock acquire time since we know that the thread was willing to yield
614 // the lock at this time.
615 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
616 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
617 return false;
618 }
619 setTransactionSuccessful();
Fred Quintanac4516a72009-09-03 12:14:06 -0700620 SQLiteTransactionListener transactionListener = mTransactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 endTransaction();
622 if (checkFullyYielded) {
623 if (this.isDbLockedByCurrentThread()) {
624 throw new IllegalStateException(
625 "Db locked more than once. yielfIfContended cannot yield");
626 }
627 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700628 if (sleepAfterYieldDelay > 0) {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700629 // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
630 // check if anyone is using the database. If the database is not contended,
631 // retake the lock and return.
632 long remainingDelay = sleepAfterYieldDelay;
633 while (remainingDelay > 0) {
634 try {
635 Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
636 remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
637 } catch (InterruptedException e) {
638 Thread.interrupted();
639 }
640 remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
641 if (mLock.getQueueLength() == 0) {
642 break;
643 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700644 }
645 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700646 beginTransactionWithListener(transactionListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 return true;
648 }
649
650 /** Maps table names to info about what to which _sync_time column to set
651 * to NULL on an update. This is used to support syncing. */
652 private final Map<String, SyncUpdateInfo> mSyncUpdateInfo =
653 new HashMap<String, SyncUpdateInfo>();
654
655 public Map<String, String> getSyncedTables() {
656 synchronized(mSyncUpdateInfo) {
657 HashMap<String, String> tables = new HashMap<String, String>();
658 for (String table : mSyncUpdateInfo.keySet()) {
659 SyncUpdateInfo info = mSyncUpdateInfo.get(table);
660 if (info.deletedTable != null) {
661 tables.put(table, info.deletedTable);
662 }
663 }
664 return tables;
665 }
666 }
667
668 /**
669 * Internal class used to keep track what needs to be marked as changed
670 * when an update occurs. This is used for syncing, so the sync engine
671 * knows what data has been updated locally.
672 */
673 static private class SyncUpdateInfo {
674 /**
675 * Creates the SyncUpdateInfo class.
676 *
677 * @param masterTable The table to set _sync_time to NULL in
678 * @param deletedTable The deleted table that corresponds to the
679 * master table
680 * @param foreignKey The key that refers to the primary key in table
681 */
682 SyncUpdateInfo(String masterTable, String deletedTable,
683 String foreignKey) {
684 this.masterTable = masterTable;
685 this.deletedTable = deletedTable;
686 this.foreignKey = foreignKey;
687 }
688
689 /** The table containing the _sync_time column */
690 String masterTable;
691
692 /** The deleted table that corresponds to the master table */
693 String deletedTable;
694
695 /** The key in the local table the row in table. It may be _id, if table
696 * is the local table. */
697 String foreignKey;
698 }
699
700 /**
701 * Used to allow returning sub-classes of {@link Cursor} when calling query.
702 */
703 public interface CursorFactory {
704 /**
705 * See
706 * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver,
707 * String, SQLiteQuery)}.
708 */
709 public Cursor newCursor(SQLiteDatabase db,
710 SQLiteCursorDriver masterQuery, String editTable,
711 SQLiteQuery query);
712 }
713
714 /**
715 * Open the database according to the flags {@link #OPEN_READWRITE}
716 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
717 *
718 * <p>Sets the locale of the database to the the system's current locale.
719 * Call {@link #setLocale} if you would like something else.</p>
720 *
721 * @param path to database file to open and/or create
722 * @param factory an optional factory class that is called to instantiate a
723 * cursor when query is called, or null for default
724 * @param flags to control database access mode
725 * @return the newly opened database
726 * @throws SQLiteException if the database cannot be opened
727 */
728 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
729 SQLiteDatabase db = null;
730 try {
731 // Open the database.
732 return new SQLiteDatabase(path, factory, flags);
733 } catch (SQLiteDatabaseCorruptException e) {
734 // Try to recover from this, if we can.
735 // TODO: should we do this for other open failures?
736 Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
737 new File(path).delete();
738 return new SQLiteDatabase(path, factory, flags);
739 }
740 }
741
742 /**
743 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
744 */
745 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
746 return openOrCreateDatabase(file.getPath(), factory);
747 }
748
749 /**
750 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
751 */
752 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
753 return openDatabase(path, factory, CREATE_IF_NECESSARY);
754 }
755
756 /**
757 * Create a memory backed SQLite database. Its contents will be destroyed
758 * when the database is closed.
759 *
760 * <p>Sets the locale of the database to the the system's current locale.
761 * Call {@link #setLocale} if you would like something else.</p>
762 *
763 * @param factory an optional factory class that is called to instantiate a
764 * cursor when query is called
765 * @return a SQLiteDatabase object, or null if the database can't be created
766 */
767 public static SQLiteDatabase create(CursorFactory factory) {
768 // This is a magic string with special meaning for SQLite.
769 return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
770 }
771
772 /**
773 * Close the database.
774 */
775 public void close() {
776 lock();
777 try {
778 closeClosable();
779 releaseReference();
780 } finally {
781 unlock();
782 }
783 }
784
785 private void closeClosable() {
786 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
787 while (iter.hasNext()) {
788 Map.Entry<SQLiteClosable, Object> entry = iter.next();
789 SQLiteClosable program = entry.getKey();
790 if (program != null) {
791 program.onAllReferencesReleasedFromContainer();
792 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 /**
797 * Native call to close the database.
798 */
799 private native void dbclose();
800
801 /**
802 * Gets the database version.
803 *
804 * @return the database version
805 */
806 public int getVersion() {
807 SQLiteStatement prog = null;
808 lock();
809 try {
810 prog = new SQLiteStatement(this, "PRAGMA user_version;");
811 long version = prog.simpleQueryForLong();
812 return (int) version;
813 } finally {
814 if (prog != null) prog.close();
815 unlock();
816 }
817 }
818
819 /**
820 * Sets the database version.
821 *
822 * @param version the new database version
823 */
824 public void setVersion(int version) {
825 execSQL("PRAGMA user_version = " + version);
826 }
827
828 /**
829 * Returns the maximum size the database may grow to.
830 *
831 * @return the new maximum database size
832 */
833 public long getMaximumSize() {
834 SQLiteStatement prog = null;
835 lock();
836 try {
837 prog = new SQLiteStatement(this,
838 "PRAGMA max_page_count;");
839 long pageCount = prog.simpleQueryForLong();
840 return pageCount * getPageSize();
841 } finally {
842 if (prog != null) prog.close();
843 unlock();
844 }
845 }
846
847 /**
848 * Sets the maximum size the database will grow to. The maximum size cannot
849 * be set below the current size.
850 *
851 * @param numBytes the maximum database size, in bytes
852 * @return the new maximum database size
853 */
854 public long setMaximumSize(long numBytes) {
855 SQLiteStatement prog = null;
856 lock();
857 try {
858 long pageSize = getPageSize();
859 long numPages = numBytes / pageSize;
860 // If numBytes isn't a multiple of pageSize, bump up a page
861 if ((numBytes % pageSize) != 0) {
862 numPages++;
863 }
864 prog = new SQLiteStatement(this,
865 "PRAGMA max_page_count = " + numPages);
866 long newPageCount = prog.simpleQueryForLong();
867 return newPageCount * pageSize;
868 } finally {
869 if (prog != null) prog.close();
870 unlock();
871 }
872 }
873
874 /**
875 * Returns the current database page size, in bytes.
876 *
877 * @return the database page size, in bytes
878 */
879 public long getPageSize() {
880 SQLiteStatement prog = null;
881 lock();
882 try {
883 prog = new SQLiteStatement(this,
884 "PRAGMA page_size;");
885 long size = prog.simpleQueryForLong();
886 return size;
887 } finally {
888 if (prog != null) prog.close();
889 unlock();
890 }
891 }
892
893 /**
894 * Sets the database page size. The page size must be a power of two. This
895 * method does not work if any data has been written to the database file,
896 * and must be called right after the database has been created.
897 *
898 * @param numBytes the database page size, in bytes
899 */
900 public void setPageSize(long numBytes) {
901 execSQL("PRAGMA page_size = " + numBytes);
902 }
903
904 /**
905 * Mark this table as syncable. When an update occurs in this table the
906 * _sync_dirty field will be set to ensure proper syncing operation.
907 *
908 * @param table the table to mark as syncable
909 * @param deletedTable The deleted table that corresponds to the
910 * syncable table
911 */
912 public void markTableSyncable(String table, String deletedTable) {
913 markTableSyncable(table, "_id", table, deletedTable);
914 }
915
916 /**
917 * Mark this table as syncable, with the _sync_dirty residing in another
918 * table. When an update occurs in this table the _sync_dirty field of the
919 * row in updateTable with the _id in foreignKey will be set to
920 * ensure proper syncing operation.
921 *
922 * @param table an update on this table will trigger a sync time removal
923 * @param foreignKey this is the column in table whose value is an _id in
924 * updateTable
925 * @param updateTable this is the table that will have its _sync_dirty
926 */
927 public void markTableSyncable(String table, String foreignKey,
928 String updateTable) {
929 markTableSyncable(table, foreignKey, updateTable, null);
930 }
931
932 /**
933 * Mark this table as syncable, with the _sync_dirty residing in another
934 * table. When an update occurs in this table the _sync_dirty field of the
935 * row in updateTable with the _id in foreignKey will be set to
936 * ensure proper syncing operation.
937 *
938 * @param table an update on this table will trigger a sync time removal
939 * @param foreignKey this is the column in table whose value is an _id in
940 * updateTable
941 * @param updateTable this is the table that will have its _sync_dirty
942 * @param deletedTable The deleted table that corresponds to the
943 * updateTable
944 */
945 private void markTableSyncable(String table, String foreignKey,
946 String updateTable, String deletedTable) {
947 lock();
948 try {
949 native_execSQL("SELECT _sync_dirty FROM " + updateTable
950 + " LIMIT 0");
951 native_execSQL("SELECT " + foreignKey + " FROM " + table
952 + " LIMIT 0");
953 } finally {
954 unlock();
955 }
956
957 SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable,
958 foreignKey);
959 synchronized (mSyncUpdateInfo) {
960 mSyncUpdateInfo.put(table, info);
961 }
962 }
963
964 /**
965 * Call for each row that is updated in a cursor.
966 *
967 * @param table the table the row is in
968 * @param rowId the row ID of the updated row
969 */
970 /* package */ void rowUpdated(String table, long rowId) {
971 SyncUpdateInfo info;
972 synchronized (mSyncUpdateInfo) {
973 info = mSyncUpdateInfo.get(table);
974 }
975 if (info != null) {
976 execSQL("UPDATE " + info.masterTable
977 + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
978 + " FROM " + table + " WHERE _id=" + rowId + ")");
979 }
980 }
981
982 /**
983 * Finds the name of the first table, which is editable.
984 *
985 * @param tables a list of tables
986 * @return the first table listed
987 */
988 public static String findEditTable(String tables) {
989 if (!TextUtils.isEmpty(tables)) {
990 // find the first word terminated by either a space or a comma
991 int spacepos = tables.indexOf(' ');
992 int commapos = tables.indexOf(',');
993
994 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
995 return tables.substring(0, spacepos);
996 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
997 return tables.substring(0, commapos);
998 }
999 return tables;
1000 } else {
1001 throw new IllegalStateException("Invalid tables");
1002 }
1003 }
1004
1005 /**
1006 * Compiles an SQL statement into a reusable pre-compiled statement object.
1007 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1008 * statement and fill in those values with {@link SQLiteProgram#bindString}
1009 * and {@link SQLiteProgram#bindLong} each time you want to run the
1010 * statement. Statements may not return result sets larger than 1x1.
1011 *
1012 * @param sql The raw SQL statement, may contain ? for unknown values to be
1013 * bound later.
1014 * @return a pre-compiled statement object.
1015 */
1016 public SQLiteStatement compileStatement(String sql) throws SQLException {
1017 lock();
1018 try {
1019 return new SQLiteStatement(this, sql);
1020 } finally {
1021 unlock();
1022 }
1023 }
1024
1025 /**
1026 * Query the given URL, returning a {@link Cursor} over the result set.
1027 *
1028 * @param distinct true if you want each row to be unique, false otherwise.
1029 * @param table The table name to compile the query against.
1030 * @param columns A list of which columns to return. Passing null will
1031 * return all columns, which is discouraged to prevent reading
1032 * data from storage that isn't going to be used.
1033 * @param selection A filter declaring which rows to return, formatted as an
1034 * SQL WHERE clause (excluding the WHERE itself). Passing null
1035 * will return all rows for the given table.
1036 * @param selectionArgs You may include ?s in selection, which will be
1037 * replaced by the values from selectionArgs, in order that they
1038 * appear in the selection. The values will be bound as Strings.
1039 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1040 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1041 * will cause the rows to not be grouped.
1042 * @param having A filter declare which row groups to include in the cursor,
1043 * if row grouping is being used, formatted as an SQL HAVING
1044 * clause (excluding the HAVING itself). Passing null will cause
1045 * all row groups to be included, and is required when row
1046 * grouping is not being used.
1047 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1048 * (excluding the ORDER BY itself). Passing null will use the
1049 * default sort order, which may be unordered.
1050 * @param limit Limits the number of rows returned by the query,
1051 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1052 * @return A Cursor object, which is positioned before the first entry
1053 * @see Cursor
1054 */
1055 public Cursor query(boolean distinct, String table, String[] columns,
1056 String selection, String[] selectionArgs, String groupBy,
1057 String having, String orderBy, String limit) {
1058 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1059 groupBy, having, orderBy, limit);
1060 }
1061
1062 /**
1063 * Query the given URL, returning a {@link Cursor} over the result set.
1064 *
1065 * @param cursorFactory the cursor factory to use, or null for the default factory
1066 * @param distinct true if you want each row to be unique, false otherwise.
1067 * @param table The table name to compile the query against.
1068 * @param columns A list of which columns to return. Passing null will
1069 * return all columns, which is discouraged to prevent reading
1070 * data from storage that isn't going to be used.
1071 * @param selection A filter declaring which rows to return, formatted as an
1072 * SQL WHERE clause (excluding the WHERE itself). Passing null
1073 * will return all rows for the given table.
1074 * @param selectionArgs You may include ?s in selection, which will be
1075 * replaced by the values from selectionArgs, in order that they
1076 * appear in the selection. The values will be bound as Strings.
1077 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1078 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1079 * will cause the rows to not be grouped.
1080 * @param having A filter declare which row groups to include in the cursor,
1081 * if row grouping is being used, formatted as an SQL HAVING
1082 * clause (excluding the HAVING itself). Passing null will cause
1083 * all row groups to be included, and is required when row
1084 * grouping is not being used.
1085 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1086 * (excluding the ORDER BY itself). Passing null will use the
1087 * default sort order, which may be unordered.
1088 * @param limit Limits the number of rows returned by the query,
1089 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1090 * @return A Cursor object, which is positioned before the first entry
1091 * @see Cursor
1092 */
1093 public Cursor queryWithFactory(CursorFactory cursorFactory,
1094 boolean distinct, String table, String[] columns,
1095 String selection, String[] selectionArgs, String groupBy,
1096 String having, String orderBy, String limit) {
1097 String sql = SQLiteQueryBuilder.buildQueryString(
1098 distinct, table, columns, selection, groupBy, having, orderBy, limit);
1099
1100 return rawQueryWithFactory(
1101 cursorFactory, sql, selectionArgs, findEditTable(table));
1102 }
1103
1104 /**
1105 * Query the given table, returning a {@link Cursor} over the result set.
1106 *
1107 * @param table The table name to compile the query against.
1108 * @param columns A list of which columns to return. Passing null will
1109 * return all columns, which is discouraged to prevent reading
1110 * data from storage that isn't going to be used.
1111 * @param selection A filter declaring which rows to return, formatted as an
1112 * SQL WHERE clause (excluding the WHERE itself). Passing null
1113 * will return all rows for the given table.
1114 * @param selectionArgs You may include ?s in selection, which will be
1115 * replaced by the values from selectionArgs, in order that they
1116 * appear in the selection. The values will be bound as Strings.
1117 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1118 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1119 * will cause the rows to not be grouped.
1120 * @param having A filter declare which row groups to include in the cursor,
1121 * if row grouping is being used, formatted as an SQL HAVING
1122 * clause (excluding the HAVING itself). Passing null will cause
1123 * all row groups to be included, and is required when row
1124 * grouping is not being used.
1125 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1126 * (excluding the ORDER BY itself). Passing null will use the
1127 * default sort order, which may be unordered.
1128 * @return A {@link Cursor} object, which is positioned before the first entry
1129 * @see Cursor
1130 */
1131 public Cursor query(String table, String[] columns, String selection,
1132 String[] selectionArgs, String groupBy, String having,
1133 String orderBy) {
1134
1135 return query(false, table, columns, selection, selectionArgs, groupBy,
1136 having, orderBy, null /* limit */);
1137 }
1138
1139 /**
1140 * Query the given table, returning a {@link Cursor} over the result set.
1141 *
1142 * @param table The table name to compile the query against.
1143 * @param columns A list of which columns to return. Passing null will
1144 * return all columns, which is discouraged to prevent reading
1145 * data from storage that isn't going to be used.
1146 * @param selection A filter declaring which rows to return, formatted as an
1147 * SQL WHERE clause (excluding the WHERE itself). Passing null
1148 * will return all rows for the given table.
1149 * @param selectionArgs You may include ?s in selection, which will be
1150 * replaced by the values from selectionArgs, in order that they
1151 * appear in the selection. The values will be bound as Strings.
1152 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1153 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1154 * will cause the rows to not be grouped.
1155 * @param having A filter declare which row groups to include in the cursor,
1156 * if row grouping is being used, formatted as an SQL HAVING
1157 * clause (excluding the HAVING itself). Passing null will cause
1158 * all row groups to be included, and is required when row
1159 * grouping is not being used.
1160 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1161 * (excluding the ORDER BY itself). Passing null will use the
1162 * default sort order, which may be unordered.
1163 * @param limit Limits the number of rows returned by the query,
1164 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1165 * @return A {@link Cursor} object, which is positioned before the first entry
1166 * @see Cursor
1167 */
1168 public Cursor query(String table, String[] columns, String selection,
1169 String[] selectionArgs, String groupBy, String having,
1170 String orderBy, String limit) {
1171
1172 return query(false, table, columns, selection, selectionArgs, groupBy,
1173 having, orderBy, limit);
1174 }
1175
1176 /**
1177 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1178 *
1179 * @param sql the SQL query. The SQL string must not be ; terminated
1180 * @param selectionArgs You may include ?s in where clause in the query,
1181 * which will be replaced by the values from selectionArgs. The
1182 * values will be bound as Strings.
1183 * @return A {@link Cursor} object, which is positioned before the first entry
1184 */
1185 public Cursor rawQuery(String sql, String[] selectionArgs) {
1186 return rawQueryWithFactory(null, sql, selectionArgs, null);
1187 }
1188
1189 /**
1190 * Runs the provided SQL and returns a cursor over the result set.
1191 *
1192 * @param cursorFactory the cursor factory to use, or null for the default factory
1193 * @param sql the SQL query. The SQL string must not be ; terminated
1194 * @param selectionArgs You may include ?s in where clause in the query,
1195 * which will be replaced by the values from selectionArgs. The
1196 * values will be bound as Strings.
1197 * @param editTable the name of the first table, which is editable
1198 * @return A {@link Cursor} object, which is positioned before the first entry
1199 */
1200 public Cursor rawQueryWithFactory(
1201 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1202 String editTable) {
1203 long timeStart = 0;
1204
1205 if (Config.LOGV) {
1206 timeStart = System.currentTimeMillis();
1207 }
1208
1209 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
1210
1211 try {
1212 return driver.query(
1213 cursorFactory != null ? cursorFactory : mFactory,
1214 selectionArgs);
1215 } finally {
1216 if (Config.LOGV) {
1217 long duration = System.currentTimeMillis() - timeStart;
1218
1219 Log.v(SQLiteCursor.TAG,
1220 "query (" + duration + " ms): " + driver.toString() + ", args are "
1221 + (selectionArgs != null
1222 ? TextUtils.join(",", selectionArgs)
1223 : "<null>"));
1224 }
1225 }
1226 }
1227
1228 /**
1229 * Runs the provided SQL and returns a cursor over the result set.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001230 * The cursor will read an initial set of rows and the return to the caller.
1231 * It will continue to read in batches and send data changed notifications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 * when the later batches are ready.
1233 * @param sql the SQL query. The SQL string must not be ; terminated
1234 * @param selectionArgs You may include ?s in where clause in the query,
1235 * which will be replaced by the values from selectionArgs. The
1236 * values will be bound as Strings.
1237 * @param initialRead set the initial count of items to read from the cursor
1238 * @param maxRead set the count of items to read on each iteration after the first
1239 * @return A {@link Cursor} object, which is positioned before the first entry
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001240 *
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001241 * This work is incomplete and not fully tested or reviewed, so currently
1242 * hidden.
1243 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001245 public Cursor rawQuery(String sql, String[] selectionArgs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 int initialRead, int maxRead) {
1247 SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1248 null, sql, selectionArgs, null);
1249 c.setLoadStyle(initialRead, maxRead);
1250 return c;
1251 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 /**
1254 * Convenience method for inserting a row into the database.
1255 *
1256 * @param table the table to insert the row into
1257 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1258 * so if initialValues is empty this column will explicitly be
1259 * assigned a NULL value
1260 * @param values this map contains the initial column values for the
1261 * row. The keys should be the column names and the values the
1262 * column values
1263 * @return the row ID of the newly inserted row, or -1 if an error occurred
1264 */
1265 public long insert(String table, String nullColumnHack, ContentValues values) {
1266 try {
1267 return insertWithOnConflict(table, nullColumnHack, values, null);
1268 } catch (SQLException e) {
1269 Log.e(TAG, "Error inserting " + values, e);
1270 return -1;
1271 }
1272 }
1273
1274 /**
1275 * Convenience method for inserting a row into the database.
1276 *
1277 * @param table the table to insert the row into
1278 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1279 * so if initialValues is empty this column will explicitly be
1280 * assigned a NULL value
1281 * @param values this map contains the initial column values for the
1282 * row. The keys should be the column names and the values the
1283 * column values
1284 * @throws SQLException
1285 * @return the row ID of the newly inserted row, or -1 if an error occurred
1286 */
1287 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1288 throws SQLException {
1289 return insertWithOnConflict(table, nullColumnHack, values, null);
1290 }
1291
1292 /**
1293 * Convenience method for replacing a row in the database.
1294 *
1295 * @param table the table in which to replace the row
1296 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1297 * so if initialValues is empty this row will explicitly be
1298 * assigned a NULL value
1299 * @param initialValues this map contains the initial column values for
1300 * the row. The key
1301 * @return the row ID of the newly inserted row, or -1 if an error occurred
1302 */
1303 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1304 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001305 return insertWithOnConflict(table, nullColumnHack, initialValues,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 ConflictAlgorithm.REPLACE);
1307 } catch (SQLException e) {
1308 Log.e(TAG, "Error inserting " + initialValues, e);
1309 return -1;
1310 }
1311 }
1312
1313 /**
1314 * Convenience method for replacing a row in the database.
1315 *
1316 * @param table the table in which to replace the row
1317 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1318 * so if initialValues is empty this row will explicitly be
1319 * assigned a NULL value
1320 * @param initialValues this map contains the initial column values for
1321 * the row. The key
1322 * @throws SQLException
1323 * @return the row ID of the newly inserted row, or -1 if an error occurred
1324 */
1325 public long replaceOrThrow(String table, String nullColumnHack,
1326 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001327 return insertWithOnConflict(table, nullColumnHack, initialValues,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 ConflictAlgorithm.REPLACE);
1329 }
1330
1331 /**
1332 * General method for inserting a row into the database.
1333 *
1334 * @param table the table to insert the row into
1335 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1336 * so if initialValues is empty this column will explicitly be
1337 * assigned a NULL value
1338 * @param initialValues this map contains the initial column values for the
1339 * row. The keys should be the column names and the values the
1340 * column values
1341 * @param algorithm {@link ConflictAlgorithm} for insert conflict resolver
1342 * @return the row ID of the newly inserted row, or -1 if an error occurred
1343 * @hide
1344 */
1345 public long insertWithOnConflict(String table, String nullColumnHack,
1346 ContentValues initialValues, ConflictAlgorithm algorithm) {
1347 if (!isOpen()) {
1348 throw new IllegalStateException("database not open");
1349 }
1350
1351 // Measurements show most sql lengths <= 152
1352 StringBuilder sql = new StringBuilder(152);
1353 sql.append("INSERT");
1354 if (algorithm != null) {
1355 sql.append(" OR ");
1356 sql.append(algorithm.value());
1357 }
1358 sql.append(" INTO ");
1359 sql.append(table);
1360 // Measurements show most values lengths < 40
1361 StringBuilder values = new StringBuilder(40);
1362
1363 Set<Map.Entry<String, Object>> entrySet = null;
1364 if (initialValues != null && initialValues.size() > 0) {
1365 entrySet = initialValues.valueSet();
1366 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1367 sql.append('(');
1368
1369 boolean needSeparator = false;
1370 while (entriesIter.hasNext()) {
1371 if (needSeparator) {
1372 sql.append(", ");
1373 values.append(", ");
1374 }
1375 needSeparator = true;
1376 Map.Entry<String, Object> entry = entriesIter.next();
1377 sql.append(entry.getKey());
1378 values.append('?');
1379 }
1380
1381 sql.append(')');
1382 } else {
1383 sql.append("(" + nullColumnHack + ") ");
1384 values.append("NULL");
1385 }
1386
1387 sql.append(" VALUES(");
1388 sql.append(values);
1389 sql.append(");");
1390
1391 lock();
1392 SQLiteStatement statement = null;
1393 try {
1394 statement = compileStatement(sql.toString());
1395
1396 // Bind the values
1397 if (entrySet != null) {
1398 int size = entrySet.size();
1399 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1400 for (int i = 0; i < size; i++) {
1401 Map.Entry<String, Object> entry = entriesIter.next();
1402 DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1403 }
1404 }
1405
1406 // Run the program and then cleanup
1407 statement.execute();
1408
1409 long insertedRowId = lastInsertRow();
1410 if (insertedRowId == -1) {
1411 Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1412 } else {
1413 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1414 Log.v(TAG, "Inserting row " + insertedRowId + " from "
1415 + initialValues + " using " + sql);
1416 }
1417 }
1418 return insertedRowId;
1419 } catch (SQLiteDatabaseCorruptException e) {
1420 onCorruption();
1421 throw e;
1422 } finally {
1423 if (statement != null) {
1424 statement.close();
1425 }
1426 unlock();
1427 }
1428 }
1429
1430 /**
1431 * Convenience method for deleting rows in the database.
1432 *
1433 * @param table the table to delete from
1434 * @param whereClause the optional WHERE clause to apply when deleting.
1435 * Passing null will delete all rows.
1436 * @return the number of rows affected if a whereClause is passed in, 0
1437 * otherwise. To remove all rows and get a count pass "1" as the
1438 * whereClause.
1439 */
1440 public int delete(String table, String whereClause, String[] whereArgs) {
1441 if (!isOpen()) {
1442 throw new IllegalStateException("database not open");
1443 }
1444 lock();
1445 SQLiteStatement statement = null;
1446 try {
1447 statement = compileStatement("DELETE FROM " + table
1448 + (!TextUtils.isEmpty(whereClause)
1449 ? " WHERE " + whereClause : ""));
1450 if (whereArgs != null) {
1451 int numArgs = whereArgs.length;
1452 for (int i = 0; i < numArgs; i++) {
1453 DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1454 }
1455 }
1456 statement.execute();
1457 statement.close();
1458 return lastChangeCount();
1459 } catch (SQLiteDatabaseCorruptException e) {
1460 onCorruption();
1461 throw e;
1462 } finally {
1463 if (statement != null) {
1464 statement.close();
1465 }
1466 unlock();
1467 }
1468 }
1469
1470 /**
1471 * Convenience method for updating rows in the database.
1472 *
1473 * @param table the table to update in
1474 * @param values a map from column names to new column values. null is a
1475 * valid value that will be translated to NULL.
1476 * @param whereClause the optional WHERE clause to apply when updating.
1477 * Passing null will update all rows.
1478 * @return the number of rows affected
1479 */
1480 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
1481 return updateWithOnConflict(table, values, whereClause, whereArgs, null);
1482 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 /**
1485 * Convenience method for updating rows in the database.
1486 *
1487 * @param table the table to update in
1488 * @param values a map from column names to new column values. null is a
1489 * valid value that will be translated to NULL.
1490 * @param whereClause the optional WHERE clause to apply when updating.
1491 * Passing null will update all rows.
1492 * @param algorithm {@link ConflictAlgorithm} for update conflict resolver
1493 * @return the number of rows affected
1494 * @hide
1495 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001496 public int updateWithOnConflict(String table, ContentValues values,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) {
1498 if (!isOpen()) {
1499 throw new IllegalStateException("database not open");
1500 }
1501
1502 if (values == null || values.size() == 0) {
1503 throw new IllegalArgumentException("Empty values");
1504 }
1505
1506 StringBuilder sql = new StringBuilder(120);
1507 sql.append("UPDATE ");
1508 if (algorithm != null) {
Bjorn Bringert7f4c2ea2009-07-22 12:49:17 +01001509 sql.append("OR ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 sql.append(algorithm.value());
Bjorn Bringert7f4c2ea2009-07-22 12:49:17 +01001511 sql.append(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 sql.append(table);
1515 sql.append(" SET ");
1516
1517 Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1518 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1519
1520 while (entriesIter.hasNext()) {
1521 Map.Entry<String, Object> entry = entriesIter.next();
1522 sql.append(entry.getKey());
1523 sql.append("=?");
1524 if (entriesIter.hasNext()) {
1525 sql.append(", ");
1526 }
1527 }
1528
1529 if (!TextUtils.isEmpty(whereClause)) {
1530 sql.append(" WHERE ");
1531 sql.append(whereClause);
1532 }
1533
1534 lock();
1535 SQLiteStatement statement = null;
1536 try {
1537 statement = compileStatement(sql.toString());
1538
1539 // Bind the values
1540 int size = entrySet.size();
1541 entriesIter = entrySet.iterator();
1542 int bindArg = 1;
1543 for (int i = 0; i < size; i++) {
1544 Map.Entry<String, Object> entry = entriesIter.next();
1545 DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1546 bindArg++;
1547 }
1548
1549 if (whereArgs != null) {
1550 size = whereArgs.length;
1551 for (int i = 0; i < size; i++) {
1552 statement.bindString(bindArg, whereArgs[i]);
1553 bindArg++;
1554 }
1555 }
1556
1557 // Run the program and then cleanup
1558 statement.execute();
1559 statement.close();
1560 int numChangedRows = lastChangeCount();
1561 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1562 Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1563 }
1564 return numChangedRows;
1565 } catch (SQLiteDatabaseCorruptException e) {
1566 onCorruption();
1567 throw e;
1568 } catch (SQLException e) {
1569 Log.e(TAG, "Error updating " + values + " using " + sql);
1570 throw e;
1571 } finally {
1572 if (statement != null) {
1573 statement.close();
1574 }
1575 unlock();
1576 }
1577 }
1578
1579 /**
1580 * Execute a single SQL statement that is not a query. For example, CREATE
1581 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1582 * supported. it takes a write lock
1583 *
1584 * @throws SQLException If the SQL string is invalid for some reason
1585 */
1586 public void execSQL(String sql) throws SQLException {
1587 boolean logStats = mLogStats;
1588 long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1589 lock();
1590 try {
1591 native_execSQL(sql);
1592 } catch (SQLiteDatabaseCorruptException e) {
1593 onCorruption();
1594 throw e;
1595 } finally {
1596 unlock();
1597 }
1598 if (logStats) {
1599 logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1600 }
1601 }
1602
1603 /**
1604 * Execute a single SQL statement that is not a query. For example, CREATE
1605 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1606 * supported. it takes a write lock,
1607 *
1608 * @param sql
1609 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1610 * @throws SQLException If the SQL string is invalid for some reason
1611 */
1612 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1613 if (bindArgs == null) {
1614 throw new IllegalArgumentException("Empty bindArgs");
1615 }
1616
1617 boolean logStats = mLogStats;
1618 long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
1619 lock();
1620 SQLiteStatement statement = null;
1621 try {
1622 statement = compileStatement(sql);
1623 if (bindArgs != null) {
1624 int numArgs = bindArgs.length;
1625 for (int i = 0; i < numArgs; i++) {
1626 DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1627 }
1628 }
1629 statement.execute();
1630 } catch (SQLiteDatabaseCorruptException e) {
1631 onCorruption();
1632 throw e;
1633 } finally {
1634 if (statement != null) {
1635 statement.close();
1636 }
1637 unlock();
1638 }
1639 if (logStats) {
1640 logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
1641 }
1642 }
1643
1644 @Override
1645 protected void finalize() {
1646 if (isOpen()) {
1647 if (mPrograms.isEmpty()) {
1648 Log.e(TAG, "Leak found", mLeakedException);
1649 } else {
1650 IllegalStateException leakProgram = new IllegalStateException(
1651 "mPrograms size " + mPrograms.size(), mLeakedException);
1652 Log.e(TAG, "Leak found", leakProgram);
1653 }
1654 closeClosable();
1655 onAllReferencesReleased();
1656 }
1657 }
1658
1659 /**
1660 * Private constructor. See {@link #create} and {@link #openDatabase}.
1661 *
1662 * @param path The full path to the database
1663 * @param factory The factory to use when creating cursors, may be NULL.
1664 * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
1665 * exists, mFlags will be updated appropriately.
1666 */
1667 private SQLiteDatabase(String path, CursorFactory factory, int flags) {
1668 if (path == null) {
1669 throw new IllegalArgumentException("path should not be null");
1670 }
1671 mFlags = flags;
1672 mPath = path;
1673 mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 mLeakedException = new IllegalStateException(path +
1676 " SQLiteDatabase created and never closed");
1677 mFactory = factory;
1678 dbopen(mPath, mFlags);
1679 mPrograms = new WeakHashMap<SQLiteClosable,Object>();
1680 try {
1681 setLocale(Locale.getDefault());
1682 } catch (RuntimeException e) {
1683 Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
1684 dbclose();
1685 throw e;
1686 }
1687 }
1688
1689 /**
1690 * return whether the DB is opened as read only.
1691 * @return true if DB is opened as read only
1692 */
1693 public boolean isReadOnly() {
1694 return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1695 }
1696
1697 /**
1698 * @return true if the DB is currently open (has not been closed)
1699 */
1700 public boolean isOpen() {
1701 return mNativeHandle != 0;
1702 }
1703
1704 public boolean needUpgrade(int newVersion) {
1705 return newVersion > getVersion();
1706 }
1707
1708 /**
1709 * Getter for the path to the database file.
1710 *
1711 * @return the path to our database file.
1712 */
1713 public final String getPath() {
1714 return mPath;
1715 }
1716
1717 /* package */ void logTimeStat(boolean read, long begin, long end) {
1718 EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
1719 }
1720
1721 /**
1722 * Sets the locale for this database. Does nothing if this database has
1723 * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
1724 * @throws SQLException if the locale could not be set. The most common reason
1725 * for this is that there is no collator available for the locale you requested.
1726 * In this case the database remains unchanged.
1727 */
1728 public void setLocale(Locale locale) {
1729 lock();
1730 try {
1731 native_setLocale(locale.toString(), mFlags);
1732 } finally {
1733 unlock();
1734 }
1735 }
1736
1737 /**
1738 * Native call to open the database.
1739 *
1740 * @param path The full path to the database
1741 */
1742 private native void dbopen(String path, int flags);
1743
1744 /**
1745 * Native call to execute a raw SQL statement. {@link #lock} must be held
1746 * when calling this method.
1747 *
1748 * @param sql The raw SQL string
1749 * @throws SQLException
1750 */
1751 /* package */ native void native_execSQL(String sql) throws SQLException;
1752
1753 /**
1754 * Native call to set the locale. {@link #lock} must be held when calling
1755 * this method.
1756 * @throws SQLException
1757 */
1758 /* package */ native void native_setLocale(String loc, int flags);
1759
1760 /**
1761 * Returns the row ID of the last row inserted into the database.
1762 *
1763 * @return the row ID of the last row inserted into the database.
1764 */
1765 /* package */ native long lastInsertRow();
1766
1767 /**
1768 * Returns the number of changes made in the last statement executed.
1769 *
1770 * @return the number of changes made in the last statement executed.
1771 */
1772 /* package */ native int lastChangeCount();
1773}