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