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.annotation.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.app.ActivityManager;
24 import android.content.ContentValues;
25 import android.database.Cursor;
26 import android.database.DatabaseErrorHandler;
27 import android.database.DatabaseUtils;
28 import android.database.DefaultDatabaseErrorHandler;
29 import android.database.SQLException;
30 import android.database.sqlite.SQLiteDebug.DbStats;
31 import android.os.CancellationSignal;
32 import android.os.Looper;
33 import android.os.OperationCanceledException;
34 import android.os.SystemProperties;
35 import android.text.TextUtils;
36 import android.util.EventLog;
37 import android.util.Log;
38 import android.util.Pair;
39 import android.util.Printer;
40 
41 import com.android.internal.util.Preconditions;
42 
43 import dalvik.system.CloseGuard;
44 
45 import java.io.File;
46 import java.io.FileFilter;
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Locale;
53 import java.util.Map;
54 import java.util.WeakHashMap;
55 
56 /**
57  * Exposes methods to manage a SQLite database.
58  *
59  * <p>
60  * SQLiteDatabase has methods to create, delete, execute SQL commands, and
61  * perform other common database management tasks.
62  * </p><p>
63  * See the Notepad sample application in the SDK for an example of creating
64  * and managing a database.
65  * </p><p>
66  * Database names must be unique within an application, not across all applications.
67  * </p>
68  *
69  * <h3>Localized Collation - ORDER BY</h3>
70  * <p>
71  * In addition to SQLite's default <code>BINARY</code> collator, Android supplies
72  * two more, <code>LOCALIZED</code>, which changes with the system's current locale,
73  * and <code>UNICODE</code>, which is the Unicode Collation Algorithm and not tailored
74  * to the current locale.
75  * </p>
76  */
77 public final class SQLiteDatabase extends SQLiteClosable {
78     private static final String TAG = "SQLiteDatabase";
79 
80     private static final int EVENT_DB_CORRUPT = 75004;
81 
82     // By default idle connections are not closed
83     private static final boolean DEBUG_CLOSE_IDLE_CONNECTIONS = SystemProperties
84             .getBoolean("persist.debug.sqlite.close_idle_connections", false);
85 
86     // Stores reference to all databases opened in the current process.
87     // (The referent Object is not used at this time.)
88     // INVARIANT: Guarded by sActiveDatabases.
89     private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>();
90 
91     // Thread-local for database sessions that belong to this database.
92     // Each thread has its own database session.
93     // INVARIANT: Immutable.
94     private final ThreadLocal<SQLiteSession> mThreadSession = ThreadLocal
95             .withInitial(this::createSession);
96 
97     // The optional factory to use when creating new Cursors.  May be null.
98     // INVARIANT: Immutable.
99     private final CursorFactory mCursorFactory;
100 
101     // Error handler to be used when SQLite returns corruption errors.
102     // INVARIANT: Immutable.
103     private final DatabaseErrorHandler mErrorHandler;
104 
105     // Shared database state lock.
106     // This lock guards all of the shared state of the database, such as its
107     // configuration, whether it is open or closed, and so on.  This lock should
108     // be held for as little time as possible.
109     //
110     // The lock MUST NOT be held while attempting to acquire database connections or
111     // while executing SQL statements on behalf of the client as it can lead to deadlock.
112     //
113     // It is ok to hold the lock while reconfiguring the connection pool or dumping
114     // statistics because those operations are non-reentrant and do not try to acquire
115     // connections that might be held by other threads.
116     //
117     // Basic rule: grab the lock, access or modify global state, release the lock, then
118     // do the required SQL work.
119     private final Object mLock = new Object();
120 
121     // Warns if the database is finalized without being closed properly.
122     // INVARIANT: Guarded by mLock.
123     private final CloseGuard mCloseGuardLocked = CloseGuard.get();
124 
125     // The database configuration.
126     // INVARIANT: Guarded by mLock.
127     private final SQLiteDatabaseConfiguration mConfigurationLocked;
128 
129     // The connection pool for the database, null when closed.
130     // The pool itself is thread-safe, but the reference to it can only be acquired
131     // when the lock is held.
132     // INVARIANT: Guarded by mLock.
133     private SQLiteConnectionPool mConnectionPoolLocked;
134 
135     // True if the database has attached databases.
136     // INVARIANT: Guarded by mLock.
137     private boolean mHasAttachedDbsLocked;
138 
139     /**
140      * When a constraint violation occurs, an immediate ROLLBACK occurs,
141      * thus ending the current transaction, and the command aborts with a
142      * return code of SQLITE_CONSTRAINT. If no transaction is active
143      * (other than the implied transaction that is created on every command)
144      * then this algorithm works the same as ABORT.
145      */
146     public static final int CONFLICT_ROLLBACK = 1;
147 
148     /**
149      * When a constraint violation occurs,no ROLLBACK is executed
150      * so changes from prior commands within the same transaction
151      * are preserved. This is the default behavior.
152      */
153     public static final int CONFLICT_ABORT = 2;
154 
155     /**
156      * When a constraint violation occurs, the command aborts with a return
157      * code SQLITE_CONSTRAINT. But any changes to the database that
158      * the command made prior to encountering the constraint violation
159      * are preserved and are not backed out.
160      */
161     public static final int CONFLICT_FAIL = 3;
162 
163     /**
164      * When a constraint violation occurs, the one row that contains
165      * the constraint violation is not inserted or changed.
166      * But the command continues executing normally. Other rows before and
167      * after the row that contained the constraint violation continue to be
168      * inserted or updated normally. No error is returned.
169      */
170     public static final int CONFLICT_IGNORE = 4;
171 
172     /**
173      * When a UNIQUE constraint violation occurs, the pre-existing rows that
174      * are causing the constraint violation are removed prior to inserting
175      * or updating the current row. Thus the insert or update always occurs.
176      * The command continues executing normally. No error is returned.
177      * If a NOT NULL constraint violation occurs, the NULL value is replaced
178      * by the default value for that column. If the column has no default
179      * value, then the ABORT algorithm is used. If a CHECK constraint
180      * violation occurs then the IGNORE algorithm is used. When this conflict
181      * resolution strategy deletes rows in order to satisfy a constraint,
182      * it does not invoke delete triggers on those rows.
183      * This behavior might change in a future release.
184      */
185     public static final int CONFLICT_REPLACE = 5;
186 
187     /**
188      * Use the following when no conflict action is specified.
189      */
190     public static final int CONFLICT_NONE = 0;
191 
192     private static final String[] CONFLICT_VALUES = new String[]
193             {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
194 
195     /**
196      * Maximum Length Of A LIKE Or GLOB Pattern
197      * The pattern matching algorithm used in the default LIKE and GLOB implementation
198      * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
199      * the pattern) for certain pathological cases. To avoid denial-of-service attacks
200      * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
201      * The default value of this limit is 50000. A modern workstation can evaluate
202      * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
203      * The denial of service problem only comes into play when the pattern length gets
204      * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
205      * are at most a few dozen bytes in length, paranoid application developers may
206      * want to reduce this parameter to something in the range of a few hundred
207      * if they know that external users are able to generate arbitrary patterns.
208      */
209     public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
210 
211     /**
212      * Open flag: Flag for {@link #openDatabase} to open the database for reading and writing.
213      * If the disk is full, this may fail even before you actually write anything.
214      *
215      * {@more} Note that the value of this flag is 0, so it is the default.
216      */
217     public static final int OPEN_READWRITE = 0x00000000;          // update native code if changing
218 
219     /**
220      * Open flag: Flag for {@link #openDatabase} to open the database for reading only.
221      * This is the only reliable way to open a database if the disk may be full.
222      */
223     public static final int OPEN_READONLY = 0x00000001;           // update native code if changing
224 
225     private static final int OPEN_READ_MASK = 0x00000001;         // update native code if changing
226 
227     /**
228      * Open flag: Flag for {@link #openDatabase} to open the database without support for
229      * localized collators.
230      *
231      * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
232      * You must be consistent when using this flag to use the setting the database was
233      * created with.  If this is set, {@link #setLocale} will do nothing.
234      */
235     public static final int NO_LOCALIZED_COLLATORS = 0x00000010;  // update native code if changing
236 
237     /**
238      * Open flag: Flag for {@link #openDatabase} to create the database file if it does not
239      * already exist.
240      */
241     public static final int CREATE_IF_NECESSARY = 0x10000000;     // update native code if changing
242 
243     /**
244      * Open flag: Flag for {@link #openDatabase} to open the database file with
245      * write-ahead logging enabled by default.  Using this flag is more efficient
246      * than calling {@link #enableWriteAheadLogging}.
247      *
248      * Write-ahead logging cannot be used with read-only databases so the value of
249      * this flag is ignored if the database is opened read-only.
250      *
251      * @see #enableWriteAheadLogging
252      */
253     public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
254 
255     /**
256      * Open flag: Flag for {@link #openDatabase} to disable Compatibility WAL when opening database.
257      *
258      * @hide
259      */
260     public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
261 
262     /**
263      * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
264      *
265      * Each prepared-statement is between 1K - 6K, depending on the complexity of the
266      * SQL statement & schema.  A large SQL cache may use a significant amount of memory.
267      */
268     public static final int MAX_SQL_CACHE_SIZE = 100;
269 
SQLiteDatabase(final String path, final int openFlags, CursorFactory cursorFactory, DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs, String journalMode, String syncMode)270     private SQLiteDatabase(final String path, final int openFlags,
271             CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
272             int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs,
273             String journalMode, String syncMode) {
274         mCursorFactory = cursorFactory;
275         mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
276         mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
277         mConfigurationLocked.lookasideSlotSize = lookasideSlotSize;
278         mConfigurationLocked.lookasideSlotCount = lookasideSlotCount;
279         // Disable lookaside allocator on low-RAM devices
280         if (ActivityManager.isLowRamDeviceStatic()) {
281             mConfigurationLocked.lookasideSlotCount = 0;
282             mConfigurationLocked.lookasideSlotSize = 0;
283         }
284         long effectiveTimeoutMs = Long.MAX_VALUE;
285         // Never close idle connections for in-memory databases
286         if (!mConfigurationLocked.isInMemoryDb()) {
287             // First, check app-specific value. Otherwise use defaults
288             // -1 in idleConnectionTimeoutMs indicates unset value
289             if (idleConnectionTimeoutMs >= 0) {
290                 effectiveTimeoutMs = idleConnectionTimeoutMs;
291             } else if (DEBUG_CLOSE_IDLE_CONNECTIONS) {
292                 effectiveTimeoutMs = SQLiteGlobal.getIdleConnectionTimeout();
293             }
294         }
295         mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
296         mConfigurationLocked.journalMode = journalMode;
297         mConfigurationLocked.syncMode = syncMode;
298         if (!SQLiteGlobal.isCompatibilityWalSupported() || (
299                 SQLiteCompatibilityWalFlags.areFlagsSet() && !SQLiteCompatibilityWalFlags
300                         .isCompatibilityWalSupported())) {
301             mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
302         }
303     }
304 
305     @Override
finalize()306     protected void finalize() throws Throwable {
307         try {
308             dispose(true);
309         } finally {
310             super.finalize();
311         }
312     }
313 
314     @Override
onAllReferencesReleased()315     protected void onAllReferencesReleased() {
316         dispose(false);
317     }
318 
dispose(boolean finalized)319     private void dispose(boolean finalized) {
320         final SQLiteConnectionPool pool;
321         synchronized (mLock) {
322             if (mCloseGuardLocked != null) {
323                 if (finalized) {
324                     mCloseGuardLocked.warnIfOpen();
325                 }
326                 mCloseGuardLocked.close();
327             }
328 
329             pool = mConnectionPoolLocked;
330             mConnectionPoolLocked = null;
331         }
332 
333         if (!finalized) {
334             synchronized (sActiveDatabases) {
335                 sActiveDatabases.remove(this);
336             }
337 
338             if (pool != null) {
339                 pool.close();
340             }
341         }
342     }
343 
344     /**
345      * Attempts to release memory that SQLite holds but does not require to
346      * operate properly. Typically this memory will come from the page cache.
347      *
348      * @return the number of bytes actually released
349      */
releaseMemory()350     public static int releaseMemory() {
351         return SQLiteGlobal.releaseMemory();
352     }
353 
354     /**
355      * Control whether or not the SQLiteDatabase is made thread-safe by using locks
356      * around critical sections. This is pretty expensive, so if you know that your
357      * DB will only be used by a single thread then you should set this to false.
358      * The default is true.
359      * @param lockingEnabled set to true to enable locks, false otherwise
360      *
361      * @deprecated This method now does nothing.  Do not use.
362      */
363     @Deprecated
setLockingEnabled(boolean lockingEnabled)364     public void setLockingEnabled(boolean lockingEnabled) {
365     }
366 
367     /**
368      * Gets a label to use when describing the database in log messages.
369      * @return The label.
370      */
getLabel()371     String getLabel() {
372         synchronized (mLock) {
373             return mConfigurationLocked.label;
374         }
375     }
376 
377     /**
378      * Sends a corruption message to the database error handler.
379      */
onCorruption()380     void onCorruption() {
381         EventLog.writeEvent(EVENT_DB_CORRUPT, getLabel());
382         mErrorHandler.onCorruption(this);
383     }
384 
385     /**
386      * Gets the {@link SQLiteSession} that belongs to this thread for this database.
387      * Once a thread has obtained a session, it will continue to obtain the same
388      * session even after the database has been closed (although the session will not
389      * be usable).  However, a thread that does not already have a session cannot
390      * obtain one after the database has been closed.
391      *
392      * The idea is that threads that have active connections to the database may still
393      * have work to complete even after the call to {@link #close}.  Active database
394      * connections are not actually disposed until they are released by the threads
395      * that own them.
396      *
397      * @return The session, never null.
398      *
399      * @throws IllegalStateException if the thread does not yet have a session and
400      * the database is not open.
401      */
getThreadSession()402     SQLiteSession getThreadSession() {
403         return mThreadSession.get(); // initialValue() throws if database closed
404     }
405 
createSession()406     SQLiteSession createSession() {
407         final SQLiteConnectionPool pool;
408         synchronized (mLock) {
409             throwIfNotOpenLocked();
410             pool = mConnectionPoolLocked;
411         }
412         return new SQLiteSession(pool);
413     }
414 
415     /**
416      * Gets default connection flags that are appropriate for this thread, taking into
417      * account whether the thread is acting on behalf of the UI.
418      *
419      * @param readOnly True if the connection should be read-only.
420      * @return The connection flags.
421      */
getThreadDefaultConnectionFlags(boolean readOnly)422     int getThreadDefaultConnectionFlags(boolean readOnly) {
423         int flags = readOnly ? SQLiteConnectionPool.CONNECTION_FLAG_READ_ONLY :
424                 SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY;
425         if (isMainThread()) {
426             flags |= SQLiteConnectionPool.CONNECTION_FLAG_INTERACTIVE;
427         }
428         return flags;
429     }
430 
isMainThread()431     private static boolean isMainThread() {
432         // FIXME: There should be a better way to do this.
433         // Would also be nice to have something that would work across Binder calls.
434         Looper looper = Looper.myLooper();
435         return looper != null && looper == Looper.getMainLooper();
436     }
437 
438     /**
439      * Begins a transaction in EXCLUSIVE mode.
440      * <p>
441      * Transactions can be nested.
442      * When the outer transaction is ended all of
443      * the work done in that transaction and all of the nested transactions will be committed or
444      * rolled back. The changes will be rolled back if any transaction is ended without being
445      * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
446      * </p>
447      * <p>Here is the standard idiom for transactions:
448      *
449      * <pre>
450      *   db.beginTransaction();
451      *   try {
452      *     ...
453      *     db.setTransactionSuccessful();
454      *   } finally {
455      *     db.endTransaction();
456      *   }
457      * </pre>
458      */
beginTransaction()459     public void beginTransaction() {
460         beginTransaction(null /* transactionStatusCallback */, true);
461     }
462 
463     /**
464      * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
465      * the outer transaction is ended all of the work done in that transaction
466      * and all of the nested transactions will be committed or rolled back. The
467      * changes will be rolled back if any transaction is ended without being
468      * marked as clean (by calling setTransactionSuccessful). Otherwise they
469      * will be committed.
470      * <p>
471      * Here is the standard idiom for transactions:
472      *
473      * <pre>
474      *   db.beginTransactionNonExclusive();
475      *   try {
476      *     ...
477      *     db.setTransactionSuccessful();
478      *   } finally {
479      *     db.endTransaction();
480      *   }
481      * </pre>
482      */
beginTransactionNonExclusive()483     public void beginTransactionNonExclusive() {
484         beginTransaction(null /* transactionStatusCallback */, false);
485     }
486 
487     /**
488      * Begins a transaction in EXCLUSIVE mode.
489      * <p>
490      * Transactions can be nested.
491      * When the outer transaction is ended all of
492      * the work done in that transaction and all of the nested transactions will be committed or
493      * rolled back. The changes will be rolled back if any transaction is ended without being
494      * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
495      * </p>
496      * <p>Here is the standard idiom for transactions:
497      *
498      * <pre>
499      *   db.beginTransactionWithListener(listener);
500      *   try {
501      *     ...
502      *     db.setTransactionSuccessful();
503      *   } finally {
504      *     db.endTransaction();
505      *   }
506      * </pre>
507      *
508      * @param transactionListener listener that should be notified when the transaction begins,
509      * commits, or is rolled back, either explicitly or by a call to
510      * {@link #yieldIfContendedSafely}.
511      */
beginTransactionWithListener(SQLiteTransactionListener transactionListener)512     public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
513         beginTransaction(transactionListener, true);
514     }
515 
516     /**
517      * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
518      * the outer transaction is ended all of the work done in that transaction
519      * and all of the nested transactions will be committed or rolled back. The
520      * changes will be rolled back if any transaction is ended without being
521      * marked as clean (by calling setTransactionSuccessful). Otherwise they
522      * will be committed.
523      * <p>
524      * Here is the standard idiom for transactions:
525      *
526      * <pre>
527      *   db.beginTransactionWithListenerNonExclusive(listener);
528      *   try {
529      *     ...
530      *     db.setTransactionSuccessful();
531      *   } finally {
532      *     db.endTransaction();
533      *   }
534      * </pre>
535      *
536      * @param transactionListener listener that should be notified when the
537      *            transaction begins, commits, or is rolled back, either
538      *            explicitly or by a call to {@link #yieldIfContendedSafely}.
539      */
beginTransactionWithListenerNonExclusive( SQLiteTransactionListener transactionListener)540     public void beginTransactionWithListenerNonExclusive(
541             SQLiteTransactionListener transactionListener) {
542         beginTransaction(transactionListener, false);
543     }
544 
beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive)545     private void beginTransaction(SQLiteTransactionListener transactionListener,
546             boolean exclusive) {
547         acquireReference();
548         try {
549             getThreadSession().beginTransaction(
550                     exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
551                             SQLiteSession.TRANSACTION_MODE_IMMEDIATE,
552                     transactionListener,
553                     getThreadDefaultConnectionFlags(false /*readOnly*/), null);
554         } finally {
555             releaseReference();
556         }
557     }
558 
559     /**
560      * End a transaction. See beginTransaction for notes about how to use this and when transactions
561      * are committed and rolled back.
562      */
endTransaction()563     public void endTransaction() {
564         acquireReference();
565         try {
566             getThreadSession().endTransaction(null);
567         } finally {
568             releaseReference();
569         }
570     }
571 
572     /**
573      * Marks the current transaction as successful. Do not do any more database work between
574      * calling this and calling endTransaction. Do as little non-database work as possible in that
575      * situation too. If any errors are encountered between this and endTransaction the transaction
576      * will still be committed.
577      *
578      * @throws IllegalStateException if the current thread is not in a transaction or the
579      * transaction is already marked as successful.
580      */
setTransactionSuccessful()581     public void setTransactionSuccessful() {
582         acquireReference();
583         try {
584             getThreadSession().setTransactionSuccessful();
585         } finally {
586             releaseReference();
587         }
588     }
589 
590     /**
591      * Returns true if the current thread has a transaction pending.
592      *
593      * @return True if the current thread is in a transaction.
594      */
inTransaction()595     public boolean inTransaction() {
596         acquireReference();
597         try {
598             return getThreadSession().hasTransaction();
599         } finally {
600             releaseReference();
601         }
602     }
603 
604     /**
605      * Returns true if the current thread is holding an active connection to the database.
606      * <p>
607      * The name of this method comes from a time when having an active connection
608      * to the database meant that the thread was holding an actual lock on the
609      * database.  Nowadays, there is no longer a true "database lock" although threads
610      * may block if they cannot acquire a database connection to perform a
611      * particular operation.
612      * </p>
613      *
614      * @return True if the current thread is holding an active connection to the database.
615      */
isDbLockedByCurrentThread()616     public boolean isDbLockedByCurrentThread() {
617         acquireReference();
618         try {
619             return getThreadSession().hasConnection();
620         } finally {
621             releaseReference();
622         }
623     }
624 
625     /**
626      * Always returns false.
627      * <p>
628      * There is no longer the concept of a database lock, so this method always returns false.
629      * </p>
630      *
631      * @return False.
632      * @deprecated Always returns false.  Do not use this method.
633      */
634     @Deprecated
isDbLockedByOtherThreads()635     public boolean isDbLockedByOtherThreads() {
636         return false;
637     }
638 
639     /**
640      * Temporarily end the transaction to let other threads run. The transaction is assumed to be
641      * successful so far. Do not call setTransactionSuccessful before calling this. When this
642      * returns a new transaction will have been created but not marked as successful.
643      * @return true if the transaction was yielded
644      * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
645      *   will not be yielded. Use yieldIfContendedSafely instead.
646      */
647     @Deprecated
yieldIfContended()648     public boolean yieldIfContended() {
649         return yieldIfContendedHelper(false /* do not check yielding */,
650                 -1 /* sleepAfterYieldDelay */);
651     }
652 
653     /**
654      * Temporarily end the transaction to let other threads run. The transaction is assumed to be
655      * successful so far. Do not call setTransactionSuccessful before calling this. When this
656      * returns a new transaction will have been created but not marked as successful. This assumes
657      * that there are no nested transactions (beginTransaction has only been called once) and will
658      * throw an exception if that is not the case.
659      * @return true if the transaction was yielded
660      */
yieldIfContendedSafely()661     public boolean yieldIfContendedSafely() {
662         return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
663     }
664 
665     /**
666      * Temporarily end the transaction to let other threads run. The transaction is assumed to be
667      * successful so far. Do not call setTransactionSuccessful before calling this. When this
668      * returns a new transaction will have been created but not marked as successful. This assumes
669      * that there are no nested transactions (beginTransaction has only been called once) and will
670      * throw an exception if that is not the case.
671      * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
672      *   the lock was actually yielded. This will allow other background threads to make some
673      *   more progress than they would if we started the transaction immediately.
674      * @return true if the transaction was yielded
675      */
yieldIfContendedSafely(long sleepAfterYieldDelay)676     public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
677         return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
678     }
679 
yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYieldDelay)680     private boolean yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYieldDelay) {
681         acquireReference();
682         try {
683             return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe, null);
684         } finally {
685             releaseReference();
686         }
687     }
688 
689     /**
690      * Deprecated.
691      * @deprecated This method no longer serves any useful purpose and has been deprecated.
692      */
693     @Deprecated
getSyncedTables()694     public Map<String, String> getSyncedTables() {
695         return new HashMap<String, String>(0);
696     }
697 
698     /**
699      * Open the database according to the flags {@link #OPEN_READWRITE}
700      * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
701      *
702      * <p>Sets the locale of the database to the  the system's current locale.
703      * Call {@link #setLocale} if you would like something else.</p>
704      *
705      * @param path to database file to open and/or create
706      * @param factory an optional factory class that is called to instantiate a
707      *            cursor when query is called, or null for default
708      * @param flags to control database access mode
709      * @return the newly opened database
710      * @throws SQLiteException if the database cannot be opened
711      */
openDatabase(@onNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags)712     public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
713             @DatabaseOpenFlags int flags) {
714         return openDatabase(path, factory, flags, null);
715     }
716 
717     /**
718      * Open the database according to the specified {@link OpenParams parameters}
719      *
720      * @param path path to database file to open and/or create.
721      * <p><strong>Important:</strong> The file should be constructed either from an absolute path or
722      * by using {@link android.content.Context#getDatabasePath(String)}.
723      * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}
724      * @return the newly opened database
725      * @throws SQLiteException if the database cannot be opened
726      */
openDatabase(@onNull File path, @NonNull OpenParams openParams)727     public static SQLiteDatabase openDatabase(@NonNull File path,
728             @NonNull OpenParams openParams) {
729         return openDatabase(path.getPath(), openParams);
730     }
731 
openDatabase(@onNull String path, @NonNull OpenParams openParams)732     private static SQLiteDatabase openDatabase(@NonNull String path,
733             @NonNull OpenParams openParams) {
734         Preconditions.checkArgument(openParams != null, "OpenParams cannot be null");
735         SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
736                 openParams.mCursorFactory, openParams.mErrorHandler,
737                 openParams.mLookasideSlotSize, openParams.mLookasideSlotCount,
738                 openParams.mIdleConnectionTimeout, openParams.mJournalMode, openParams.mSyncMode);
739         db.open();
740         return db;
741     }
742 
743     /**
744      * Open the database according to the flags {@link #OPEN_READWRITE}
745      * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
746      *
747      * <p>Sets the locale of the database to the  the system's current locale.
748      * Call {@link #setLocale} if you would like something else.</p>
749      *
750      * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
751      * used to handle corruption when sqlite reports database corruption.</p>
752      *
753      * @param path to database file to open and/or create
754      * @param factory an optional factory class that is called to instantiate a
755      *            cursor when query is called, or null for default
756      * @param flags to control database access mode
757      * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
758      * when sqlite reports database corruption
759      * @return the newly opened database
760      * @throws SQLiteException if the database cannot be opened
761      */
openDatabase(@onNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler)762     public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
763             @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) {
764         SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1, null,
765                 null);
766         db.open();
767         return db;
768     }
769 
770     /**
771      * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
772      */
openOrCreateDatabase(@onNull File file, @Nullable CursorFactory factory)773     public static SQLiteDatabase openOrCreateDatabase(@NonNull File file,
774             @Nullable CursorFactory factory) {
775         return openOrCreateDatabase(file.getPath(), factory);
776     }
777 
778     /**
779      * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
780      */
openOrCreateDatabase(@onNull String path, @Nullable CursorFactory factory)781     public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
782             @Nullable CursorFactory factory) {
783         return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
784     }
785 
786     /**
787      * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
788      */
openOrCreateDatabase(@onNull String path, @Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler)789     public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
790             @Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) {
791         return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
792     }
793 
794     /**
795      * Deletes a database including its journal file and other auxiliary files
796      * that may have been created by the database engine.
797      *
798      * @param file The database file path.
799      * @return True if the database was successfully deleted.
800      */
deleteDatabase(@onNull File file)801     public static boolean deleteDatabase(@NonNull File file) {
802         if (file == null) {
803             throw new IllegalArgumentException("file must not be null");
804         }
805 
806         boolean deleted = false;
807         deleted |= file.delete();
808         deleted |= new File(file.getPath() + "-journal").delete();
809         deleted |= new File(file.getPath() + "-shm").delete();
810         deleted |= new File(file.getPath() + "-wal").delete();
811 
812         File dir = file.getParentFile();
813         if (dir != null) {
814             final String prefix = file.getName() + "-mj";
815             File[] files = dir.listFiles(new FileFilter() {
816                 @Override
817                 public boolean accept(File candidate) {
818                     return candidate.getName().startsWith(prefix);
819                 }
820             });
821             if (files != null) {
822                 for (File masterJournal : files) {
823                     deleted |= masterJournal.delete();
824                 }
825             }
826         }
827         return deleted;
828     }
829 
830     /**
831      * Reopens the database in read-write mode.
832      * If the database is already read-write, does nothing.
833      *
834      * @throws SQLiteException if the database could not be reopened as requested, in which
835      * case it remains open in read only mode.
836      * @throws IllegalStateException if the database is not open.
837      *
838      * @see #isReadOnly()
839      * @hide
840      */
reopenReadWrite()841     public void reopenReadWrite() {
842         synchronized (mLock) {
843             throwIfNotOpenLocked();
844 
845             if (!isReadOnlyLocked()) {
846                 return; // nothing to do
847             }
848 
849             // Reopen the database in read-write mode.
850             final int oldOpenFlags = mConfigurationLocked.openFlags;
851             mConfigurationLocked.openFlags = (mConfigurationLocked.openFlags & ~OPEN_READ_MASK)
852                     | OPEN_READWRITE;
853             try {
854                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
855             } catch (RuntimeException ex) {
856                 mConfigurationLocked.openFlags = oldOpenFlags;
857                 throw ex;
858             }
859         }
860     }
861 
open()862     private void open() {
863         try {
864             try {
865                 openInner();
866             } catch (SQLiteDatabaseCorruptException ex) {
867                 onCorruption();
868                 openInner();
869             }
870         } catch (SQLiteException ex) {
871             Log.e(TAG, "Failed to open database '" + getLabel() + "'.", ex);
872             close();
873             throw ex;
874         }
875     }
876 
openInner()877     private void openInner() {
878         synchronized (mLock) {
879             assert mConnectionPoolLocked == null;
880             mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked);
881             mCloseGuardLocked.open("close");
882         }
883 
884         synchronized (sActiveDatabases) {
885             sActiveDatabases.put(this, null);
886         }
887     }
888 
889     /**
890      * Create a memory backed SQLite database.  Its contents will be destroyed
891      * when the database is closed.
892      *
893      * <p>Sets the locale of the database to the  the system's current locale.
894      * Call {@link #setLocale} if you would like something else.</p>
895      *
896      * @param factory an optional factory class that is called to instantiate a
897      *            cursor when query is called
898      * @return a SQLiteDatabase instance
899      * @throws SQLiteException if the database cannot be created
900      */
901     @NonNull
create(@ullable CursorFactory factory)902     public static SQLiteDatabase create(@Nullable CursorFactory factory) {
903         // This is a magic string with special meaning for SQLite.
904         return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
905                 factory, CREATE_IF_NECESSARY);
906     }
907 
908     /**
909      * Create a memory backed SQLite database.  Its contents will be destroyed
910      * when the database is closed.
911      *
912      * <p>Sets the locale of the database to the  the system's current locale.
913      * Call {@link #setLocale} if you would like something else.</p>
914      * @param openParams configuration parameters that are used for opening SQLiteDatabase
915      * @return a SQLiteDatabase instance
916      * @throws SQLException if the database cannot be created
917      */
918     @NonNull
createInMemory(@onNull OpenParams openParams)919     public static SQLiteDatabase createInMemory(@NonNull OpenParams openParams) {
920         return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
921                 openParams.toBuilder().addOpenFlags(CREATE_IF_NECESSARY).build());
922     }
923 
924     /**
925      * Registers a CustomFunction callback as a function that can be called from
926      * SQLite database triggers.
927      *
928      * @param name the name of the sqlite3 function
929      * @param numArgs the number of arguments for the function
930      * @param function callback to call when the function is executed
931      * @hide
932      */
addCustomFunction(String name, int numArgs, CustomFunction function)933     public void addCustomFunction(String name, int numArgs, CustomFunction function) {
934         // Create wrapper (also validates arguments).
935         SQLiteCustomFunction wrapper = new SQLiteCustomFunction(name, numArgs, function);
936 
937         synchronized (mLock) {
938             throwIfNotOpenLocked();
939 
940             mConfigurationLocked.customFunctions.add(wrapper);
941             try {
942                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
943             } catch (RuntimeException ex) {
944                 mConfigurationLocked.customFunctions.remove(wrapper);
945                 throw ex;
946             }
947         }
948     }
949 
950     /**
951      * Gets the database version.
952      *
953      * @return the database version
954      */
getVersion()955     public int getVersion() {
956         return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
957     }
958 
959     /**
960      * Sets the database version.
961      *
962      * @param version the new database version
963      */
setVersion(int version)964     public void setVersion(int version) {
965         execSQL("PRAGMA user_version = " + version);
966     }
967 
968     /**
969      * Returns the maximum size the database may grow to.
970      *
971      * @return the new maximum database size
972      */
getMaximumSize()973     public long getMaximumSize() {
974         long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
975         return pageCount * getPageSize();
976     }
977 
978     /**
979      * Sets the maximum size the database will grow to. The maximum size cannot
980      * be set below the current size.
981      *
982      * @param numBytes the maximum database size, in bytes
983      * @return the new maximum database size
984      */
setMaximumSize(long numBytes)985     public long setMaximumSize(long numBytes) {
986         long pageSize = getPageSize();
987         long numPages = numBytes / pageSize;
988         // If numBytes isn't a multiple of pageSize, bump up a page
989         if ((numBytes % pageSize) != 0) {
990             numPages++;
991         }
992         long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
993                 null);
994         return newPageCount * pageSize;
995     }
996 
997     /**
998      * Returns the current database page size, in bytes.
999      *
1000      * @return the database page size, in bytes
1001      */
getPageSize()1002     public long getPageSize() {
1003         return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
1004     }
1005 
1006     /**
1007      * Sets the database page size. The page size must be a power of two. This
1008      * method does not work if any data has been written to the database file,
1009      * and must be called right after the database has been created.
1010      *
1011      * @param numBytes the database page size, in bytes
1012      */
setPageSize(long numBytes)1013     public void setPageSize(long numBytes) {
1014         execSQL("PRAGMA page_size = " + numBytes);
1015     }
1016 
1017     /**
1018      * Mark this table as syncable. When an update occurs in this table the
1019      * _sync_dirty field will be set to ensure proper syncing operation.
1020      *
1021      * @param table the table to mark as syncable
1022      * @param deletedTable The deleted table that corresponds to the
1023      *          syncable table
1024      * @deprecated This method no longer serves any useful purpose and has been deprecated.
1025      */
1026     @Deprecated
markTableSyncable(String table, String deletedTable)1027     public void markTableSyncable(String table, String deletedTable) {
1028     }
1029 
1030     /**
1031      * Mark this table as syncable, with the _sync_dirty residing in another
1032      * table. When an update occurs in this table the _sync_dirty field of the
1033      * row in updateTable with the _id in foreignKey will be set to
1034      * ensure proper syncing operation.
1035      *
1036      * @param table an update on this table will trigger a sync time removal
1037      * @param foreignKey this is the column in table whose value is an _id in
1038      *          updateTable
1039      * @param updateTable this is the table that will have its _sync_dirty
1040      * @deprecated This method no longer serves any useful purpose and has been deprecated.
1041      */
1042     @Deprecated
markTableSyncable(String table, String foreignKey, String updateTable)1043     public void markTableSyncable(String table, String foreignKey, String updateTable) {
1044     }
1045 
1046     /**
1047      * Finds the name of the first table, which is editable.
1048      *
1049      * @param tables a list of tables
1050      * @return the first table listed
1051      */
findEditTable(String tables)1052     public static String findEditTable(String tables) {
1053         if (!TextUtils.isEmpty(tables)) {
1054             // find the first word terminated by either a space or a comma
1055             int spacepos = tables.indexOf(' ');
1056             int commapos = tables.indexOf(',');
1057 
1058             if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1059                 return tables.substring(0, spacepos);
1060             } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1061                 return tables.substring(0, commapos);
1062             }
1063             return tables;
1064         } else {
1065             throw new IllegalStateException("Invalid tables");
1066         }
1067     }
1068 
1069     /**
1070      * Compiles an SQL statement into a reusable pre-compiled statement object.
1071      * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1072      * statement and fill in those values with {@link SQLiteProgram#bindString}
1073      * and {@link SQLiteProgram#bindLong} each time you want to run the
1074      * statement. Statements may not return result sets larger than 1x1.
1075      *<p>
1076      * No two threads should be using the same {@link SQLiteStatement} at the same time.
1077      *
1078      * @param sql The raw SQL statement, may contain ? for unknown values to be
1079      *            bound later.
1080      * @return A pre-compiled {@link SQLiteStatement} object. Note that
1081      * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
1082      */
compileStatement(String sql)1083     public SQLiteStatement compileStatement(String sql) throws SQLException {
1084         acquireReference();
1085         try {
1086             return new SQLiteStatement(this, sql, null);
1087         } finally {
1088             releaseReference();
1089         }
1090     }
1091 
1092     /**
1093      * Query the given URL, returning a {@link Cursor} over the result set.
1094      *
1095      * @param distinct true if you want each row to be unique, false otherwise.
1096      * @param table The table name to compile the query against.
1097      * @param columns A list of which columns to return. Passing null will
1098      *            return all columns, which is discouraged to prevent reading
1099      *            data from storage that isn't going to be used.
1100      * @param selection A filter declaring which rows to return, formatted as an
1101      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1102      *            will return all rows for the given table.
1103      * @param selectionArgs You may include ?s in selection, which will be
1104      *         replaced by the values from selectionArgs, in order that they
1105      *         appear in the selection. The values will be bound as Strings.
1106      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1107      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1108      *            will cause the rows to not be grouped.
1109      * @param having A filter declare which row groups to include in the cursor,
1110      *            if row grouping is being used, formatted as an SQL HAVING
1111      *            clause (excluding the HAVING itself). Passing null will cause
1112      *            all row groups to be included, and is required when row
1113      *            grouping is not being used.
1114      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1115      *            (excluding the ORDER BY itself). Passing null will use the
1116      *            default sort order, which may be unordered.
1117      * @param limit Limits the number of rows returned by the query,
1118      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1119      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1120      * {@link Cursor}s are not synchronized, see the documentation for more details.
1121      * @see Cursor
1122      */
query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)1123     public Cursor query(boolean distinct, String table, String[] columns,
1124             String selection, String[] selectionArgs, String groupBy,
1125             String having, String orderBy, String limit) {
1126         return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1127                 groupBy, having, orderBy, limit, null);
1128     }
1129 
1130     /**
1131      * Query the given URL, returning a {@link Cursor} over the result set.
1132      *
1133      * @param distinct true if you want each row to be unique, false otherwise.
1134      * @param table The table name to compile the query against.
1135      * @param columns A list of which columns to return. Passing null will
1136      *            return all columns, which is discouraged to prevent reading
1137      *            data from storage that isn't going to be used.
1138      * @param selection A filter declaring which rows to return, formatted as an
1139      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1140      *            will return all rows for the given table.
1141      * @param selectionArgs You may include ?s in selection, which will be
1142      *         replaced by the values from selectionArgs, in order that they
1143      *         appear in the selection. The values will be bound as Strings.
1144      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1145      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1146      *            will cause the rows to not be grouped.
1147      * @param having A filter declare which row groups to include in the cursor,
1148      *            if row grouping is being used, formatted as an SQL HAVING
1149      *            clause (excluding the HAVING itself). Passing null will cause
1150      *            all row groups to be included, and is required when row
1151      *            grouping is not being used.
1152      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1153      *            (excluding the ORDER BY itself). Passing null will use the
1154      *            default sort order, which may be unordered.
1155      * @param limit Limits the number of rows returned by the query,
1156      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1157      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1158      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1159      * when the query is executed.
1160      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1161      * {@link Cursor}s are not synchronized, see the documentation for more details.
1162      * @see Cursor
1163      */
query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)1164     public Cursor query(boolean distinct, String table, String[] columns,
1165             String selection, String[] selectionArgs, String groupBy,
1166             String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
1167         return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1168                 groupBy, having, orderBy, limit, cancellationSignal);
1169     }
1170 
1171     /**
1172      * Query the given URL, returning a {@link Cursor} over the result set.
1173      *
1174      * @param cursorFactory the cursor factory to use, or null for the default factory
1175      * @param distinct true if you want each row to be unique, false otherwise.
1176      * @param table The table name to compile the query against.
1177      * @param columns A list of which columns to return. Passing null will
1178      *            return all columns, which is discouraged to prevent reading
1179      *            data from storage that isn't going to be used.
1180      * @param selection A filter declaring which rows to return, formatted as an
1181      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1182      *            will return all rows for the given table.
1183      * @param selectionArgs You may include ?s in selection, which will be
1184      *         replaced by the values from selectionArgs, in order that they
1185      *         appear in the selection. The values will be bound as Strings.
1186      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1187      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1188      *            will cause the rows to not be grouped.
1189      * @param having A filter declare which row groups to include in the cursor,
1190      *            if row grouping is being used, formatted as an SQL HAVING
1191      *            clause (excluding the HAVING itself). Passing null will cause
1192      *            all row groups to be included, and is required when row
1193      *            grouping is not being used.
1194      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1195      *            (excluding the ORDER BY itself). Passing null will use the
1196      *            default sort order, which may be unordered.
1197      * @param limit Limits the number of rows returned by the query,
1198      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1199      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1200      * {@link Cursor}s are not synchronized, see the documentation for more details.
1201      * @see Cursor
1202      */
queryWithFactory(CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)1203     public Cursor queryWithFactory(CursorFactory cursorFactory,
1204             boolean distinct, String table, String[] columns,
1205             String selection, String[] selectionArgs, String groupBy,
1206             String having, String orderBy, String limit) {
1207         return queryWithFactory(cursorFactory, distinct, table, columns, selection,
1208                 selectionArgs, groupBy, having, orderBy, limit, null);
1209     }
1210 
1211     /**
1212      * Query the given URL, returning a {@link Cursor} over the result set.
1213      *
1214      * @param cursorFactory the cursor factory to use, or null for the default factory
1215      * @param distinct true if you want each row to be unique, false otherwise.
1216      * @param table The table name to compile the query against.
1217      * @param columns A list of which columns to return. Passing null will
1218      *            return all columns, which is discouraged to prevent reading
1219      *            data from storage that isn't going to be used.
1220      * @param selection A filter declaring which rows to return, formatted as an
1221      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1222      *            will return all rows for the given table.
1223      * @param selectionArgs You may include ?s in selection, which will be
1224      *         replaced by the values from selectionArgs, in order that they
1225      *         appear in the selection. The values will be bound as Strings.
1226      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1227      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1228      *            will cause the rows to not be grouped.
1229      * @param having A filter declare which row groups to include in the cursor,
1230      *            if row grouping is being used, formatted as an SQL HAVING
1231      *            clause (excluding the HAVING itself). Passing null will cause
1232      *            all row groups to be included, and is required when row
1233      *            grouping is not being used.
1234      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1235      *            (excluding the ORDER BY itself). Passing null will use the
1236      *            default sort order, which may be unordered.
1237      * @param limit Limits the number of rows returned by the query,
1238      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1239      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1240      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1241      * when the query is executed.
1242      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1243      * {@link Cursor}s are not synchronized, see the documentation for more details.
1244      * @see Cursor
1245      */
queryWithFactory(CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)1246     public Cursor queryWithFactory(CursorFactory cursorFactory,
1247             boolean distinct, String table, String[] columns,
1248             String selection, String[] selectionArgs, String groupBy,
1249             String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
1250         acquireReference();
1251         try {
1252             String sql = SQLiteQueryBuilder.buildQueryString(
1253                     distinct, table, columns, selection, groupBy, having, orderBy, limit);
1254 
1255             return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
1256                     findEditTable(table), cancellationSignal);
1257         } finally {
1258             releaseReference();
1259         }
1260     }
1261 
1262     /**
1263      * Query the given table, returning a {@link Cursor} over the result set.
1264      *
1265      * @param table The table name to compile the query against.
1266      * @param columns A list of which columns to return. Passing null will
1267      *            return all columns, which is discouraged to prevent reading
1268      *            data from storage that isn't going to be used.
1269      * @param selection A filter declaring which rows to return, formatted as an
1270      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1271      *            will return all rows for the given table.
1272      * @param selectionArgs You may include ?s in selection, which will be
1273      *         replaced by the values from selectionArgs, in order that they
1274      *         appear in the selection. The values will be bound as Strings.
1275      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1276      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1277      *            will cause the rows to not be grouped.
1278      * @param having A filter declare which row groups to include in the cursor,
1279      *            if row grouping is being used, formatted as an SQL HAVING
1280      *            clause (excluding the HAVING itself). Passing null will cause
1281      *            all row groups to be included, and is required when row
1282      *            grouping is not being used.
1283      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1284      *            (excluding the ORDER BY itself). Passing null will use the
1285      *            default sort order, which may be unordered.
1286      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1287      * {@link Cursor}s are not synchronized, see the documentation for more details.
1288      * @see Cursor
1289      */
query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)1290     public Cursor query(String table, String[] columns, String selection,
1291             String[] selectionArgs, String groupBy, String having,
1292             String orderBy) {
1293 
1294         return query(false, table, columns, selection, selectionArgs, groupBy,
1295                 having, orderBy, null /* limit */);
1296     }
1297 
1298     /**
1299      * Query the given table, returning a {@link Cursor} over the result set.
1300      *
1301      * @param table The table name to compile the query against.
1302      * @param columns A list of which columns to return. Passing null will
1303      *            return all columns, which is discouraged to prevent reading
1304      *            data from storage that isn't going to be used.
1305      * @param selection A filter declaring which rows to return, formatted as an
1306      *            SQL WHERE clause (excluding the WHERE itself). Passing null
1307      *            will return all rows for the given table.
1308      * @param selectionArgs You may include ?s in selection, which will be
1309      *         replaced by the values from selectionArgs, in order that they
1310      *         appear in the selection. The values will be bound as Strings.
1311      * @param groupBy A filter declaring how to group rows, formatted as an SQL
1312      *            GROUP BY clause (excluding the GROUP BY itself). Passing null
1313      *            will cause the rows to not be grouped.
1314      * @param having A filter declare which row groups to include in the cursor,
1315      *            if row grouping is being used, formatted as an SQL HAVING
1316      *            clause (excluding the HAVING itself). Passing null will cause
1317      *            all row groups to be included, and is required when row
1318      *            grouping is not being used.
1319      * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1320      *            (excluding the ORDER BY itself). Passing null will use the
1321      *            default sort order, which may be unordered.
1322      * @param limit Limits the number of rows returned by the query,
1323      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1324      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1325      * {@link Cursor}s are not synchronized, see the documentation for more details.
1326      * @see Cursor
1327      */
query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)1328     public Cursor query(String table, String[] columns, String selection,
1329             String[] selectionArgs, String groupBy, String having,
1330             String orderBy, String limit) {
1331 
1332         return query(false, table, columns, selection, selectionArgs, groupBy,
1333                 having, orderBy, limit);
1334     }
1335 
1336     /**
1337      * Runs the provided SQL and returns a {@link Cursor} over the result set.
1338      *
1339      * @param sql the SQL query. The SQL string must not be ; terminated
1340      * @param selectionArgs You may include ?s in where clause in the query,
1341      *     which will be replaced by the values from selectionArgs. The
1342      *     values will be bound as Strings.
1343      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1344      * {@link Cursor}s are not synchronized, see the documentation for more details.
1345      */
rawQuery(String sql, String[] selectionArgs)1346     public Cursor rawQuery(String sql, String[] selectionArgs) {
1347         return rawQueryWithFactory(null, sql, selectionArgs, null, null);
1348     }
1349 
1350     /**
1351      * Runs the provided SQL and returns a {@link Cursor} over the result set.
1352      *
1353      * @param sql the SQL query. The SQL string must not be ; terminated
1354      * @param selectionArgs You may include ?s in where clause in the query,
1355      *     which will be replaced by the values from selectionArgs. The
1356      *     values will be bound as Strings.
1357      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1358      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1359      * when the query is executed.
1360      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1361      * {@link Cursor}s are not synchronized, see the documentation for more details.
1362      */
rawQuery(String sql, String[] selectionArgs, CancellationSignal cancellationSignal)1363     public Cursor rawQuery(String sql, String[] selectionArgs,
1364             CancellationSignal cancellationSignal) {
1365         return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
1366     }
1367 
1368     /**
1369      * Runs the provided SQL and returns a cursor over the result set.
1370      *
1371      * @param cursorFactory the cursor factory to use, or null for the default factory
1372      * @param sql the SQL query. The SQL string must not be ; terminated
1373      * @param selectionArgs You may include ?s in where clause in the query,
1374      *     which will be replaced by the values from selectionArgs. The
1375      *     values will be bound as Strings.
1376      * @param editTable the name of the first table, which is editable
1377      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1378      * {@link Cursor}s are not synchronized, see the documentation for more details.
1379      */
rawQueryWithFactory( CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable)1380     public Cursor rawQueryWithFactory(
1381             CursorFactory cursorFactory, String sql, String[] selectionArgs,
1382             String editTable) {
1383         return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
1384     }
1385 
1386     /**
1387      * Runs the provided SQL and returns a cursor over the result set.
1388      *
1389      * @param cursorFactory the cursor factory to use, or null for the default factory
1390      * @param sql the SQL query. The SQL string must not be ; terminated
1391      * @param selectionArgs You may include ?s in where clause in the query,
1392      *     which will be replaced by the values from selectionArgs. The
1393      *     values will be bound as Strings.
1394      * @param editTable the name of the first table, which is editable
1395      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1396      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1397      * when the query is executed.
1398      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1399      * {@link Cursor}s are not synchronized, see the documentation for more details.
1400      */
rawQueryWithFactory( CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal)1401     public Cursor rawQueryWithFactory(
1402             CursorFactory cursorFactory, String sql, String[] selectionArgs,
1403             String editTable, CancellationSignal cancellationSignal) {
1404         acquireReference();
1405         try {
1406             SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
1407                     cancellationSignal);
1408             return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
1409                     selectionArgs);
1410         } finally {
1411             releaseReference();
1412         }
1413     }
1414 
1415     /**
1416      * Convenience method for inserting a row into the database.
1417      *
1418      * @param table the table to insert the row into
1419      * @param nullColumnHack optional; may be <code>null</code>.
1420      *            SQL doesn't allow inserting a completely empty row without
1421      *            naming at least one column name.  If your provided <code>values</code> is
1422      *            empty, no column names are known and an empty row can't be inserted.
1423      *            If not set to null, the <code>nullColumnHack</code> parameter
1424      *            provides the name of nullable column name to explicitly insert a NULL into
1425      *            in the case where your <code>values</code> is empty.
1426      * @param values this map contains the initial column values for the
1427      *            row. The keys should be the column names and the values the
1428      *            column values
1429      * @return the row ID of the newly inserted row, or -1 if an error occurred
1430      */
insert(String table, String nullColumnHack, ContentValues values)1431     public long insert(String table, String nullColumnHack, ContentValues values) {
1432         try {
1433             return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
1434         } catch (SQLException e) {
1435             Log.e(TAG, "Error inserting " + values, e);
1436             return -1;
1437         }
1438     }
1439 
1440     /**
1441      * Convenience method for inserting a row into the database.
1442      *
1443      * @param table the table to insert the row into
1444      * @param nullColumnHack optional; may be <code>null</code>.
1445      *            SQL doesn't allow inserting a completely empty row without
1446      *            naming at least one column name.  If your provided <code>values</code> is
1447      *            empty, no column names are known and an empty row can't be inserted.
1448      *            If not set to null, the <code>nullColumnHack</code> parameter
1449      *            provides the name of nullable column name to explicitly insert a NULL into
1450      *            in the case where your <code>values</code> is empty.
1451      * @param values this map contains the initial column values for the
1452      *            row. The keys should be the column names and the values the
1453      *            column values
1454      * @throws SQLException
1455      * @return the row ID of the newly inserted row, or -1 if an error occurred
1456      */
insertOrThrow(String table, String nullColumnHack, ContentValues values)1457     public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1458             throws SQLException {
1459         return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
1460     }
1461 
1462     /**
1463      * Convenience method for replacing a row in the database.
1464      * Inserts a new row if a row does not already exist.
1465      *
1466      * @param table the table in which to replace the row
1467      * @param nullColumnHack optional; may be <code>null</code>.
1468      *            SQL doesn't allow inserting a completely empty row without
1469      *            naming at least one column name.  If your provided <code>initialValues</code> is
1470      *            empty, no column names are known and an empty row can't be inserted.
1471      *            If not set to null, the <code>nullColumnHack</code> parameter
1472      *            provides the name of nullable column name to explicitly insert a NULL into
1473      *            in the case where your <code>initialValues</code> is empty.
1474      * @param initialValues this map contains the initial column values for
1475      *   the row. The keys should be the column names and the values the column values.
1476      * @return the row ID of the newly inserted row, or -1 if an error occurred
1477      */
replace(String table, String nullColumnHack, ContentValues initialValues)1478     public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1479         try {
1480             return insertWithOnConflict(table, nullColumnHack, initialValues,
1481                     CONFLICT_REPLACE);
1482         } catch (SQLException e) {
1483             Log.e(TAG, "Error inserting " + initialValues, e);
1484             return -1;
1485         }
1486     }
1487 
1488     /**
1489      * Convenience method for replacing a row in the database.
1490      * Inserts a new row if a row does not already exist.
1491      *
1492      * @param table the table in which to replace the row
1493      * @param nullColumnHack optional; may be <code>null</code>.
1494      *            SQL doesn't allow inserting a completely empty row without
1495      *            naming at least one column name.  If your provided <code>initialValues</code> is
1496      *            empty, no column names are known and an empty row can't be inserted.
1497      *            If not set to null, the <code>nullColumnHack</code> parameter
1498      *            provides the name of nullable column name to explicitly insert a NULL into
1499      *            in the case where your <code>initialValues</code> is empty.
1500      * @param initialValues this map contains the initial column values for
1501      *   the row. The keys should be the column names and the values the column values.
1502      * @throws SQLException
1503      * @return the row ID of the newly inserted row, or -1 if an error occurred
1504      */
replaceOrThrow(String table, String nullColumnHack, ContentValues initialValues)1505     public long replaceOrThrow(String table, String nullColumnHack,
1506             ContentValues initialValues) throws SQLException {
1507         return insertWithOnConflict(table, nullColumnHack, initialValues,
1508                 CONFLICT_REPLACE);
1509     }
1510 
1511     /**
1512      * General method for inserting a row into the database.
1513      *
1514      * @param table the table to insert the row into
1515      * @param nullColumnHack optional; may be <code>null</code>.
1516      *            SQL doesn't allow inserting a completely empty row without
1517      *            naming at least one column name.  If your provided <code>initialValues</code> is
1518      *            empty, no column names are known and an empty row can't be inserted.
1519      *            If not set to null, the <code>nullColumnHack</code> parameter
1520      *            provides the name of nullable column name to explicitly insert a NULL into
1521      *            in the case where your <code>initialValues</code> is empty.
1522      * @param initialValues this map contains the initial column values for the
1523      *            row. The keys should be the column names and the values the
1524      *            column values
1525      * @param conflictAlgorithm for insert conflict resolver
1526      * @return the row ID of the newly inserted row OR <code>-1</code> if either the
1527      *            input parameter <code>conflictAlgorithm</code> = {@link #CONFLICT_IGNORE}
1528      *            or an error occurred.
1529      */
insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm)1530     public long insertWithOnConflict(String table, String nullColumnHack,
1531             ContentValues initialValues, int conflictAlgorithm) {
1532         acquireReference();
1533         try {
1534             StringBuilder sql = new StringBuilder();
1535             sql.append("INSERT");
1536             sql.append(CONFLICT_VALUES[conflictAlgorithm]);
1537             sql.append(" INTO ");
1538             sql.append(table);
1539             sql.append('(');
1540 
1541             Object[] bindArgs = null;
1542             int size = (initialValues != null && !initialValues.isEmpty())
1543                     ? initialValues.size() : 0;
1544             if (size > 0) {
1545                 bindArgs = new Object[size];
1546                 int i = 0;
1547                 for (String colName : initialValues.keySet()) {
1548                     sql.append((i > 0) ? "," : "");
1549                     sql.append(colName);
1550                     bindArgs[i++] = initialValues.get(colName);
1551                 }
1552                 sql.append(')');
1553                 sql.append(" VALUES (");
1554                 for (i = 0; i < size; i++) {
1555                     sql.append((i > 0) ? ",?" : "?");
1556                 }
1557             } else {
1558                 sql.append(nullColumnHack + ") VALUES (NULL");
1559             }
1560             sql.append(')');
1561 
1562             SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
1563             try {
1564                 return statement.executeInsert();
1565             } finally {
1566                 statement.close();
1567             }
1568         } finally {
1569             releaseReference();
1570         }
1571     }
1572 
1573     /**
1574      * Convenience method for deleting rows in the database.
1575      *
1576      * @param table the table to delete from
1577      * @param whereClause the optional WHERE clause to apply when deleting.
1578      *            Passing null will delete all rows.
1579      * @param whereArgs You may include ?s in the where clause, which
1580      *            will be replaced by the values from whereArgs. The values
1581      *            will be bound as Strings.
1582      * @return the number of rows affected if a whereClause is passed in, 0
1583      *         otherwise. To remove all rows and get a count pass "1" as the
1584      *         whereClause.
1585      */
delete(String table, String whereClause, String[] whereArgs)1586     public int delete(String table, String whereClause, String[] whereArgs) {
1587         acquireReference();
1588         try {
1589             SQLiteStatement statement =  new SQLiteStatement(this, "DELETE FROM " + table +
1590                     (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
1591             try {
1592                 return statement.executeUpdateDelete();
1593             } finally {
1594                 statement.close();
1595             }
1596         } finally {
1597             releaseReference();
1598         }
1599     }
1600 
1601     /**
1602      * Convenience method for updating rows in the database.
1603      *
1604      * @param table the table to update in
1605      * @param values a map from column names to new column values. null is a
1606      *            valid value that will be translated to NULL.
1607      * @param whereClause the optional WHERE clause to apply when updating.
1608      *            Passing null will update all rows.
1609      * @param whereArgs You may include ?s in the where clause, which
1610      *            will be replaced by the values from whereArgs. The values
1611      *            will be bound as Strings.
1612      * @return the number of rows affected
1613      */
update(String table, ContentValues values, String whereClause, String[] whereArgs)1614     public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
1615         return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
1616     }
1617 
1618     /**
1619      * Convenience method for updating rows in the database.
1620      *
1621      * @param table the table to update in
1622      * @param values a map from column names to new column values. null is a
1623      *            valid value that will be translated to NULL.
1624      * @param whereClause the optional WHERE clause to apply when updating.
1625      *            Passing null will update all rows.
1626      * @param whereArgs You may include ?s in the where clause, which
1627      *            will be replaced by the values from whereArgs. The values
1628      *            will be bound as Strings.
1629      * @param conflictAlgorithm for update conflict resolver
1630      * @return the number of rows affected
1631      */
updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm)1632     public int updateWithOnConflict(String table, ContentValues values,
1633             String whereClause, String[] whereArgs, int conflictAlgorithm) {
1634         if (values == null || values.isEmpty()) {
1635             throw new IllegalArgumentException("Empty values");
1636         }
1637 
1638         acquireReference();
1639         try {
1640             StringBuilder sql = new StringBuilder(120);
1641             sql.append("UPDATE ");
1642             sql.append(CONFLICT_VALUES[conflictAlgorithm]);
1643             sql.append(table);
1644             sql.append(" SET ");
1645 
1646             // move all bind args to one array
1647             int setValuesSize = values.size();
1648             int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
1649             Object[] bindArgs = new Object[bindArgsSize];
1650             int i = 0;
1651             for (String colName : values.keySet()) {
1652                 sql.append((i > 0) ? "," : "");
1653                 sql.append(colName);
1654                 bindArgs[i++] = values.get(colName);
1655                 sql.append("=?");
1656             }
1657             if (whereArgs != null) {
1658                 for (i = setValuesSize; i < bindArgsSize; i++) {
1659                     bindArgs[i] = whereArgs[i - setValuesSize];
1660                 }
1661             }
1662             if (!TextUtils.isEmpty(whereClause)) {
1663                 sql.append(" WHERE ");
1664                 sql.append(whereClause);
1665             }
1666 
1667             SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
1668             try {
1669                 return statement.executeUpdateDelete();
1670             } finally {
1671                 statement.close();
1672             }
1673         } finally {
1674             releaseReference();
1675         }
1676     }
1677 
1678     /**
1679      * Execute a single SQL statement that is NOT a SELECT
1680      * or any other SQL statement that returns data.
1681      * <p>
1682      * It has no means to return any data (such as the number of affected rows).
1683      * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
1684      * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
1685      * </p>
1686      * <p>
1687      * When using {@link #enableWriteAheadLogging()}, journal_mode is
1688      * automatically managed by this class. So, do not set journal_mode
1689      * using "PRAGMA journal_mode'<value>" statement if your app is using
1690      * {@link #enableWriteAheadLogging()}
1691      * </p>
1692      *
1693      * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1694      * not supported.
1695      * @throws SQLException if the SQL string is invalid
1696      */
execSQL(String sql)1697     public void execSQL(String sql) throws SQLException {
1698         executeSql(sql, null);
1699     }
1700 
1701     /**
1702      * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
1703      * <p>
1704      * For INSERT statements, use any of the following instead.
1705      * <ul>
1706      *   <li>{@link #insert(String, String, ContentValues)}</li>
1707      *   <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
1708      *   <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
1709      * </ul>
1710      * <p>
1711      * For UPDATE statements, use any of the following instead.
1712      * <ul>
1713      *   <li>{@link #update(String, ContentValues, String, String[])}</li>
1714      *   <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
1715      * </ul>
1716      * <p>
1717      * For DELETE statements, use any of the following instead.
1718      * <ul>
1719      *   <li>{@link #delete(String, String, String[])}</li>
1720      * </ul>
1721      * <p>
1722      * For example, the following are good candidates for using this method:
1723      * <ul>
1724      *   <li>ALTER TABLE</li>
1725      *   <li>CREATE or DROP table / trigger / view / index / virtual table</li>
1726      *   <li>REINDEX</li>
1727      *   <li>RELEASE</li>
1728      *   <li>SAVEPOINT</li>
1729      *   <li>PRAGMA that returns no data</li>
1730      * </ul>
1731      * </p>
1732      * <p>
1733      * When using {@link #enableWriteAheadLogging()}, journal_mode is
1734      * automatically managed by this class. So, do not set journal_mode
1735      * using "PRAGMA journal_mode'<value>" statement if your app is using
1736      * {@link #enableWriteAheadLogging()}
1737      * </p>
1738      *
1739      * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1740      * not supported.
1741      * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1742      * @throws SQLException if the SQL string is invalid
1743      */
execSQL(String sql, Object[] bindArgs)1744     public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1745         if (bindArgs == null) {
1746             throw new IllegalArgumentException("Empty bindArgs");
1747         }
1748         executeSql(sql, bindArgs);
1749     }
1750 
executeSql(String sql, Object[] bindArgs)1751     private int executeSql(String sql, Object[] bindArgs) throws SQLException {
1752         acquireReference();
1753         try {
1754             final int statementType = DatabaseUtils.getSqlStatementType(sql);
1755             if (statementType == DatabaseUtils.STATEMENT_ATTACH) {
1756                 boolean disableWal = false;
1757                 synchronized (mLock) {
1758                     if (!mHasAttachedDbsLocked) {
1759                         mHasAttachedDbsLocked = true;
1760                         disableWal = true;
1761                         mConnectionPoolLocked.disableIdleConnectionHandler();
1762                     }
1763                 }
1764                 if (disableWal) {
1765                     disableWriteAheadLogging();
1766                 }
1767             }
1768 
1769             try (SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs)) {
1770                 return statement.executeUpdateDelete();
1771             } finally {
1772                 // If schema was updated, close non-primary connections, otherwise they might
1773                 // have outdated schema information
1774                 if (statementType == DatabaseUtils.STATEMENT_DDL) {
1775                     mConnectionPoolLocked.closeAvailableNonPrimaryConnectionsAndLogExceptions();
1776                 }
1777             }
1778         } finally {
1779             releaseReference();
1780         }
1781     }
1782 
1783     /**
1784      * Verifies that a SQL SELECT statement is valid by compiling it.
1785      * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
1786      *
1787      * @param sql SQL to be validated
1788      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1789      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1790      * when the query is executed.
1791      * @throws SQLiteException if {@code sql} is invalid
1792      */
validateSql(@onNull String sql, @Nullable CancellationSignal cancellationSignal)1793     public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal) {
1794         getThreadSession().prepare(sql,
1795                 getThreadDefaultConnectionFlags(/* readOnly =*/ true), cancellationSignal, null);
1796     }
1797 
1798     /**
1799      * Returns true if the database is opened as read only.
1800      *
1801      * @return True if database is opened as read only.
1802      */
isReadOnly()1803     public boolean isReadOnly() {
1804         synchronized (mLock) {
1805             return isReadOnlyLocked();
1806         }
1807     }
1808 
isReadOnlyLocked()1809     private boolean isReadOnlyLocked() {
1810         return (mConfigurationLocked.openFlags & OPEN_READ_MASK) == OPEN_READONLY;
1811     }
1812 
1813     /**
1814      * Returns true if the database is in-memory db.
1815      *
1816      * @return True if the database is in-memory.
1817      * @hide
1818      */
isInMemoryDatabase()1819     public boolean isInMemoryDatabase() {
1820         synchronized (mLock) {
1821             return mConfigurationLocked.isInMemoryDb();
1822         }
1823     }
1824 
1825     /**
1826      * Returns true if the database is currently open.
1827      *
1828      * @return True if the database is currently open (has not been closed).
1829      */
isOpen()1830     public boolean isOpen() {
1831         synchronized (mLock) {
1832             return mConnectionPoolLocked != null;
1833         }
1834     }
1835 
1836     /**
1837      * Returns true if the new version code is greater than the current database version.
1838      *
1839      * @param newVersion The new version code.
1840      * @return True if the new version code is greater than the current database version.
1841      */
needUpgrade(int newVersion)1842     public boolean needUpgrade(int newVersion) {
1843         return newVersion > getVersion();
1844     }
1845 
1846     /**
1847      * Gets the path to the database file.
1848      *
1849      * @return The path to the database file.
1850      */
getPath()1851     public final String getPath() {
1852         synchronized (mLock) {
1853             return mConfigurationLocked.path;
1854         }
1855     }
1856 
1857     /**
1858      * Sets the locale for this database.  Does nothing if this database has
1859      * the {@link #NO_LOCALIZED_COLLATORS} flag set or was opened read only.
1860      *
1861      * @param locale The new locale.
1862      *
1863      * @throws SQLException if the locale could not be set.  The most common reason
1864      * for this is that there is no collator available for the locale you requested.
1865      * In this case the database remains unchanged.
1866      */
setLocale(Locale locale)1867     public void setLocale(Locale locale) {
1868         if (locale == null) {
1869             throw new IllegalArgumentException("locale must not be null.");
1870         }
1871 
1872         synchronized (mLock) {
1873             throwIfNotOpenLocked();
1874 
1875             final Locale oldLocale = mConfigurationLocked.locale;
1876             mConfigurationLocked.locale = locale;
1877             try {
1878                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1879             } catch (RuntimeException ex) {
1880                 mConfigurationLocked.locale = oldLocale;
1881                 throw ex;
1882             }
1883         }
1884     }
1885 
1886     /**
1887      * Sets the maximum size of the prepared-statement cache for this database.
1888      * (size of the cache = number of compiled-sql-statements stored in the cache).
1889      *<p>
1890      * Maximum cache size can ONLY be increased from its current size (default = 10).
1891      * If this method is called with smaller size than the current maximum value,
1892      * then IllegalStateException is thrown.
1893      *<p>
1894      * This method is thread-safe.
1895      *
1896      * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
1897      * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE}.
1898      */
setMaxSqlCacheSize(int cacheSize)1899     public void setMaxSqlCacheSize(int cacheSize) {
1900         if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
1901             throw new IllegalStateException(
1902                     "expected value between 0 and " + MAX_SQL_CACHE_SIZE);
1903         }
1904 
1905         synchronized (mLock) {
1906             throwIfNotOpenLocked();
1907 
1908             final int oldMaxSqlCacheSize = mConfigurationLocked.maxSqlCacheSize;
1909             mConfigurationLocked.maxSqlCacheSize = cacheSize;
1910             try {
1911                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1912             } catch (RuntimeException ex) {
1913                 mConfigurationLocked.maxSqlCacheSize = oldMaxSqlCacheSize;
1914                 throw ex;
1915             }
1916         }
1917     }
1918 
1919     /**
1920      * Sets whether foreign key constraints are enabled for the database.
1921      * <p>
1922      * By default, foreign key constraints are not enforced by the database.
1923      * This method allows an application to enable foreign key constraints.
1924      * It must be called each time the database is opened to ensure that foreign
1925      * key constraints are enabled for the session.
1926      * </p><p>
1927      * A good time to call this method is right after calling {@link #openOrCreateDatabase}
1928      * or in the {@link SQLiteOpenHelper#onConfigure} callback.
1929      * </p><p>
1930      * When foreign key constraints are disabled, the database does not check whether
1931      * changes to the database will violate foreign key constraints.  Likewise, when
1932      * foreign key constraints are disabled, the database will not execute cascade
1933      * delete or update triggers.  As a result, it is possible for the database
1934      * state to become inconsistent.  To perform a database integrity check,
1935      * call {@link #isDatabaseIntegrityOk}.
1936      * </p><p>
1937      * This method must not be called while a transaction is in progress.
1938      * </p><p>
1939      * See also <a href="http://sqlite.org/foreignkeys.html">SQLite Foreign Key Constraints</a>
1940      * for more details about foreign key constraint support.
1941      * </p>
1942      *
1943      * @param enable True to enable foreign key constraints, false to disable them.
1944      *
1945      * @throws IllegalStateException if the are transactions is in progress
1946      * when this method is called.
1947      */
setForeignKeyConstraintsEnabled(boolean enable)1948     public void setForeignKeyConstraintsEnabled(boolean enable) {
1949         synchronized (mLock) {
1950             throwIfNotOpenLocked();
1951 
1952             if (mConfigurationLocked.foreignKeyConstraintsEnabled == enable) {
1953                 return;
1954             }
1955 
1956             mConfigurationLocked.foreignKeyConstraintsEnabled = enable;
1957             try {
1958                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1959             } catch (RuntimeException ex) {
1960                 mConfigurationLocked.foreignKeyConstraintsEnabled = !enable;
1961                 throw ex;
1962             }
1963         }
1964     }
1965 
1966     /**
1967      * This method enables parallel execution of queries from multiple threads on the
1968      * same database.  It does this by opening multiple connections to the database
1969      * and using a different database connection for each query.  The database
1970      * journal mode is also changed to enable writes to proceed concurrently with reads.
1971      * <p>
1972      * When write-ahead logging is not enabled (the default), it is not possible for
1973      * reads and writes to occur on the database at the same time.  Before modifying the
1974      * database, the writer implicitly acquires an exclusive lock on the database which
1975      * prevents readers from accessing the database until the write is completed.
1976      * </p><p>
1977      * In contrast, when write-ahead logging is enabled (by calling this method), write
1978      * operations occur in a separate log file which allows reads to proceed concurrently.
1979      * While a write is in progress, readers on other threads will perceive the state
1980      * of the database as it was before the write began.  When the write completes, readers
1981      * on other threads will then perceive the new state of the database.
1982      * </p><p>
1983      * It is a good idea to enable write-ahead logging whenever a database will be
1984      * concurrently accessed and modified by multiple threads at the same time.
1985      * However, write-ahead logging uses significantly more memory than ordinary
1986      * journaling because there are multiple connections to the same database.
1987      * So if a database will only be used by a single thread, or if optimizing
1988      * concurrency is not very important, then write-ahead logging should be disabled.
1989      * </p><p>
1990      * After calling this method, execution of queries in parallel is enabled as long as
1991      * the database remains open.  To disable execution of queries in parallel, either
1992      * call {@link #disableWriteAheadLogging} or close the database and reopen it.
1993      * </p><p>
1994      * The maximum number of connections used to execute queries in parallel is
1995      * dependent upon the device memory and possibly other properties.
1996      * </p><p>
1997      * If a query is part of a transaction, then it is executed on the same database handle the
1998      * transaction was begun.
1999      * </p><p>
2000      * Writers should use {@link #beginTransactionNonExclusive()} or
2001      * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
2002      * to start a transaction.  Non-exclusive mode allows database file to be in readable
2003      * by other threads executing queries.
2004      * </p><p>
2005      * If the database has any attached databases, then execution of queries in parallel is NOT
2006      * possible.  Likewise, write-ahead logging is not supported for read-only databases
2007      * or memory databases.  In such cases, {@link #enableWriteAheadLogging} returns false.
2008      * </p><p>
2009      * The best way to enable write-ahead logging is to pass the
2010      * {@link #ENABLE_WRITE_AHEAD_LOGGING} flag to {@link #openDatabase}.  This is
2011      * more efficient than calling {@link #enableWriteAheadLogging}.
2012      * <code><pre>
2013      *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2014      *             SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
2015      *             myDatabaseErrorHandler);
2016      * </pre></code>
2017      * </p><p>
2018      * Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging}
2019      * after opening the database.
2020      * <code><pre>
2021      *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2022      *             SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);
2023      *     db.enableWriteAheadLogging();
2024      * </pre></code>
2025      * </p><p>
2026      * See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for
2027      * more details about how write-ahead logging works.
2028      * </p>
2029      *
2030      * @return True if write-ahead logging is enabled.
2031      *
2032      * @throws IllegalStateException if there are transactions in progress at the
2033      * time this method is called.  WAL mode can only be changed when there are no
2034      * transactions in progress.
2035      *
2036      * @see #ENABLE_WRITE_AHEAD_LOGGING
2037      * @see #disableWriteAheadLogging
2038      */
enableWriteAheadLogging()2039     public boolean enableWriteAheadLogging() {
2040         synchronized (mLock) {
2041             throwIfNotOpenLocked();
2042 
2043             if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
2044                 return true;
2045             }
2046 
2047             if (isReadOnlyLocked()) {
2048                 // WAL doesn't make sense for readonly-databases.
2049                 // TODO: True, but connection pooling does still make sense...
2050                 return false;
2051             }
2052 
2053             if (mConfigurationLocked.isInMemoryDb()) {
2054                 Log.i(TAG, "can't enable WAL for memory databases.");
2055                 return false;
2056             }
2057 
2058             // make sure this database has NO attached databases because sqlite's write-ahead-logging
2059             // doesn't work for databases with attached databases
2060             if (mHasAttachedDbsLocked) {
2061                 if (Log.isLoggable(TAG, Log.DEBUG)) {
2062                     Log.d(TAG, "this database: " + mConfigurationLocked.label
2063                             + " has attached databases. can't  enable WAL.");
2064                 }
2065                 return false;
2066             }
2067 
2068             mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
2069             try {
2070                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
2071             } catch (RuntimeException ex) {
2072                 mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
2073                 throw ex;
2074             }
2075         }
2076         return true;
2077     }
2078 
2079     /**
2080      * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
2081      *
2082      * @throws IllegalStateException if there are transactions in progress at the
2083      * time this method is called.  WAL mode can only be changed when there are no
2084      * transactions in progress.
2085      *
2086      * @see #enableWriteAheadLogging
2087      */
disableWriteAheadLogging()2088     public void disableWriteAheadLogging() {
2089         synchronized (mLock) {
2090             throwIfNotOpenLocked();
2091 
2092             final int oldFlags = mConfigurationLocked.openFlags;
2093             final boolean walDisabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0;
2094             final boolean compatibilityWalDisabled = (oldFlags & DISABLE_COMPATIBILITY_WAL) != 0;
2095             if (walDisabled && compatibilityWalDisabled) {
2096                 return;
2097             }
2098 
2099             mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
2100             // If an app explicitly disables WAL, compatibility mode should be disabled too
2101             mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
2102 
2103             try {
2104                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
2105             } catch (RuntimeException ex) {
2106                 mConfigurationLocked.openFlags = oldFlags;
2107                 throw ex;
2108             }
2109         }
2110     }
2111 
2112     /**
2113      * Returns true if write-ahead logging has been enabled for this database.
2114      *
2115      * @return True if write-ahead logging has been enabled for this database.
2116      *
2117      * @see #enableWriteAheadLogging
2118      * @see #ENABLE_WRITE_AHEAD_LOGGING
2119      */
isWriteAheadLoggingEnabled()2120     public boolean isWriteAheadLoggingEnabled() {
2121         synchronized (mLock) {
2122             throwIfNotOpenLocked();
2123 
2124             return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
2125         }
2126     }
2127 
2128     /**
2129      * Collect statistics about all open databases in the current process.
2130      * Used by bug report.
2131      */
getDbStats()2132     static ArrayList<DbStats> getDbStats() {
2133         ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
2134         for (SQLiteDatabase db : getActiveDatabases()) {
2135             db.collectDbStats(dbStatsList);
2136         }
2137         return dbStatsList;
2138     }
2139 
collectDbStats(ArrayList<DbStats> dbStatsList)2140     private void collectDbStats(ArrayList<DbStats> dbStatsList) {
2141         synchronized (mLock) {
2142             if (mConnectionPoolLocked != null) {
2143                 mConnectionPoolLocked.collectDbStats(dbStatsList);
2144             }
2145         }
2146     }
2147 
getActiveDatabases()2148     private static ArrayList<SQLiteDatabase> getActiveDatabases() {
2149         ArrayList<SQLiteDatabase> databases = new ArrayList<SQLiteDatabase>();
2150         synchronized (sActiveDatabases) {
2151             databases.addAll(sActiveDatabases.keySet());
2152         }
2153         return databases;
2154     }
2155 
2156     /**
2157      * Dump detailed information about all open databases in the current process.
2158      * Used by bug report.
2159      */
dumpAll(Printer printer, boolean verbose)2160     static void dumpAll(Printer printer, boolean verbose) {
2161         for (SQLiteDatabase db : getActiveDatabases()) {
2162             db.dump(printer, verbose);
2163         }
2164     }
2165 
dump(Printer printer, boolean verbose)2166     private void dump(Printer printer, boolean verbose) {
2167         synchronized (mLock) {
2168             if (mConnectionPoolLocked != null) {
2169                 printer.println("");
2170                 mConnectionPoolLocked.dump(printer, verbose);
2171             }
2172         }
2173     }
2174 
2175     /**
2176      * Returns list of full pathnames of all attached databases including the main database
2177      * by executing 'pragma database_list' on the database.
2178      *
2179      * @return ArrayList of pairs of (database name, database file path) or null if the database
2180      * is not open.
2181      */
getAttachedDbs()2182     public List<Pair<String, String>> getAttachedDbs() {
2183         ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
2184         synchronized (mLock) {
2185             if (mConnectionPoolLocked == null) {
2186                 return null; // not open
2187             }
2188 
2189             if (!mHasAttachedDbsLocked) {
2190                 // No attached databases.
2191                 // There is a small window where attached databases exist but this flag is not
2192                 // set yet.  This can occur when this thread is in a race condition with another
2193                 // thread that is executing the SQL statement: "attach database <blah> as <foo>"
2194                 // If this thread is NOT ok with such a race condition (and thus possibly not
2195                 // receivethe entire list of attached databases), then the caller should ensure
2196                 // that no thread is executing any SQL statements while a thread is calling this
2197                 // method.  Typically, this method is called when 'adb bugreport' is done or the
2198                 // caller wants to collect stats on the database and all its attached databases.
2199                 attachedDbs.add(new Pair<String, String>("main", mConfigurationLocked.path));
2200                 return attachedDbs;
2201             }
2202 
2203             acquireReference();
2204         }
2205 
2206         try {
2207             // has attached databases. query sqlite to get the list of attached databases.
2208             Cursor c = null;
2209             try {
2210                 c = rawQuery("pragma database_list;", null);
2211                 while (c.moveToNext()) {
2212                     // sqlite returns a row for each database in the returned list of databases.
2213                     //   in each row,
2214                     //       1st column is the database name such as main, or the database
2215                     //                              name specified on the "ATTACH" command
2216                     //       2nd column is the database file path.
2217                     attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
2218                 }
2219             } finally {
2220                 if (c != null) {
2221                     c.close();
2222                 }
2223             }
2224             return attachedDbs;
2225         } finally {
2226             releaseReference();
2227         }
2228     }
2229 
2230     /**
2231      * Runs 'pragma integrity_check' on the given database (and all the attached databases)
2232      * and returns true if the given database (and all its attached databases) pass integrity_check,
2233      * false otherwise.
2234      *<p>
2235      * If the result is false, then this method logs the errors reported by the integrity_check
2236      * command execution.
2237      *<p>
2238      * Note that 'pragma integrity_check' on a database can take a long time.
2239      *
2240      * @return true if the given database (and all its attached databases) pass integrity_check,
2241      * false otherwise.
2242      */
isDatabaseIntegrityOk()2243     public boolean isDatabaseIntegrityOk() {
2244         acquireReference();
2245         try {
2246             List<Pair<String, String>> attachedDbs = null;
2247             try {
2248                 attachedDbs = getAttachedDbs();
2249                 if (attachedDbs == null) {
2250                     throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
2251                             "be retrieved. probably because the database is closed");
2252                 }
2253             } catch (SQLiteException e) {
2254                 // can't get attachedDb list. do integrity check on the main database
2255                 attachedDbs = new ArrayList<Pair<String, String>>();
2256                 attachedDbs.add(new Pair<String, String>("main", getPath()));
2257             }
2258 
2259             for (int i = 0; i < attachedDbs.size(); i++) {
2260                 Pair<String, String> p = attachedDbs.get(i);
2261                 SQLiteStatement prog = null;
2262                 try {
2263                     prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);");
2264                     String rslt = prog.simpleQueryForString();
2265                     if (!rslt.equalsIgnoreCase("ok")) {
2266                         // integrity_checker failed on main or attached databases
2267                         Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt);
2268                         return false;
2269                     }
2270                 } finally {
2271                     if (prog != null) prog.close();
2272                 }
2273             }
2274         } finally {
2275             releaseReference();
2276         }
2277         return true;
2278     }
2279 
2280     @Override
toString()2281     public String toString() {
2282         return "SQLiteDatabase: " + getPath();
2283     }
2284 
throwIfNotOpenLocked()2285     private void throwIfNotOpenLocked() {
2286         if (mConnectionPoolLocked == null) {
2287             throw new IllegalStateException("The database '" + mConfigurationLocked.label
2288                     + "' is not open.");
2289         }
2290     }
2291 
2292     /**
2293      * Used to allow returning sub-classes of {@link Cursor} when calling query.
2294      */
2295     public interface CursorFactory {
2296         /**
2297          * See {@link SQLiteCursor#SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)}.
2298          */
newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query)2299         public Cursor newCursor(SQLiteDatabase db,
2300                 SQLiteCursorDriver masterQuery, String editTable,
2301                 SQLiteQuery query);
2302     }
2303 
2304     /**
2305      * A callback interface for a custom sqlite3 function.
2306      * This can be used to create a function that can be called from
2307      * sqlite3 database triggers.
2308      * @hide
2309      */
2310     public interface CustomFunction {
callback(String[] args)2311         public void callback(String[] args);
2312     }
2313 
2314     /**
2315      * Wrapper for configuration parameters that are used for opening {@link SQLiteDatabase}
2316      */
2317     public static final class OpenParams {
2318         private final int mOpenFlags;
2319         private final CursorFactory mCursorFactory;
2320         private final DatabaseErrorHandler mErrorHandler;
2321         private final int mLookasideSlotSize;
2322         private final int mLookasideSlotCount;
2323         private final long mIdleConnectionTimeout;
2324         private final String mJournalMode;
2325         private final String mSyncMode;
2326 
OpenParams(int openFlags, CursorFactory cursorFactory, DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeout, String journalMode, String syncMode)2327         private OpenParams(int openFlags, CursorFactory cursorFactory,
2328                 DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
2329                 long idleConnectionTimeout, String journalMode, String syncMode) {
2330             mOpenFlags = openFlags;
2331             mCursorFactory = cursorFactory;
2332             mErrorHandler = errorHandler;
2333             mLookasideSlotSize = lookasideSlotSize;
2334             mLookasideSlotCount = lookasideSlotCount;
2335             mIdleConnectionTimeout = idleConnectionTimeout;
2336             mJournalMode = journalMode;
2337             mSyncMode = syncMode;
2338         }
2339 
2340         /**
2341          * Returns size in bytes of each lookaside slot or -1 if not set.
2342          *
2343          * @see Builder#setLookasideConfig(int, int)
2344          */
2345         @IntRange(from = -1)
getLookasideSlotSize()2346         public int getLookasideSlotSize() {
2347             return mLookasideSlotSize;
2348         }
2349 
2350         /**
2351          * Returns total number of lookaside memory slots per database connection or -1 if not
2352          * set.
2353          *
2354          * @see Builder#setLookasideConfig(int, int)
2355          */
2356         @IntRange(from = -1)
getLookasideSlotCount()2357         public int getLookasideSlotCount() {
2358             return mLookasideSlotCount;
2359         }
2360 
2361         /**
2362          * Returns flags to control database access mode. Default value is 0.
2363          *
2364          * @see Builder#setOpenFlags(int)
2365          */
2366         @DatabaseOpenFlags
getOpenFlags()2367         public int getOpenFlags() {
2368             return mOpenFlags;
2369         }
2370 
2371         /**
2372          * Returns an optional factory class that is called to instantiate a cursor when query
2373          * is called
2374          *
2375          * @see Builder#setCursorFactory(CursorFactory)
2376          */
2377         @Nullable
getCursorFactory()2378         public CursorFactory getCursorFactory() {
2379             return mCursorFactory;
2380         }
2381 
2382         /**
2383          * Returns handler for database corruption errors
2384          *
2385          * @see Builder#setErrorHandler(DatabaseErrorHandler)
2386          */
2387         @Nullable
getErrorHandler()2388         public DatabaseErrorHandler getErrorHandler() {
2389             return mErrorHandler;
2390         }
2391 
2392         /**
2393          * Returns maximum number of milliseconds that SQLite connection is allowed to be idle
2394          * before it is closed and removed from the pool.
2395          * <p>If the value isn't set, the timeout defaults to the system wide timeout
2396          *
2397          * @return timeout in milliseconds or -1 if the value wasn't set.
2398          */
getIdleConnectionTimeout()2399         public long getIdleConnectionTimeout() {
2400             return mIdleConnectionTimeout;
2401         }
2402 
2403         /**
2404          * Returns <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>.
2405          * This journal mode will only be used if {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING}
2406          * flag is not set, otherwise a platform will use "WAL" journal mode.
2407          * @see Builder#setJournalMode(String)
2408          */
2409         @Nullable
getJournalMode()2410         public String getJournalMode() {
2411             return mJournalMode;
2412         }
2413 
2414         /**
2415          * Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>.
2416          * If not set, a system wide default will be used.
2417          * @see Builder#setSynchronousMode(String)
2418          */
2419         @Nullable
getSynchronousMode()2420         public String getSynchronousMode() {
2421             return mSyncMode;
2422         }
2423 
2424         /**
2425          * Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
2426          * {@code this} parameters.
2427          * @hide
2428          */
2429         @NonNull
toBuilder()2430         public Builder toBuilder() {
2431             return new Builder(this);
2432         }
2433 
2434         /**
2435          * Builder for {@link OpenParams}.
2436          */
2437         public static final class Builder {
2438             private int mLookasideSlotSize = -1;
2439             private int mLookasideSlotCount = -1;
2440             private long mIdleConnectionTimeout = -1;
2441             private int mOpenFlags;
2442             private CursorFactory mCursorFactory;
2443             private DatabaseErrorHandler mErrorHandler;
2444             private String mJournalMode;
2445             private String mSyncMode;
2446 
Builder()2447             public Builder() {
2448             }
2449 
Builder(OpenParams params)2450             public Builder(OpenParams params) {
2451                 mLookasideSlotSize = params.mLookasideSlotSize;
2452                 mLookasideSlotCount = params.mLookasideSlotCount;
2453                 mOpenFlags = params.mOpenFlags;
2454                 mCursorFactory = params.mCursorFactory;
2455                 mErrorHandler = params.mErrorHandler;
2456                 mJournalMode = params.mJournalMode;
2457                 mSyncMode = params.mSyncMode;
2458             }
2459 
2460             /**
2461              * Configures
2462              * <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
2463              *
2464              * <p>SQLite default settings will be used, if this method isn't called.
2465              * Use {@code setLookasideConfig(0,0)} to disable lookaside
2466              *
2467              * <p><strong>Note:</strong> Provided slotSize/slotCount configuration is just a
2468              * recommendation. The system may choose different values depending on a device, e.g.
2469              * lookaside allocations can be disabled on low-RAM devices
2470              *
2471              * @param slotSize The size in bytes of each lookaside slot.
2472              * @param slotCount The total number of lookaside memory slots per database connection.
2473              */
setLookasideConfig(@ntRangefrom = 0) final int slotSize, @IntRange(from = 0) final int slotCount)2474             public Builder setLookasideConfig(@IntRange(from = 0) final int slotSize,
2475                     @IntRange(from = 0) final int slotCount) {
2476                 Preconditions.checkArgument(slotSize >= 0,
2477                         "lookasideSlotCount cannot be negative");
2478                 Preconditions.checkArgument(slotCount >= 0,
2479                         "lookasideSlotSize cannot be negative");
2480                 Preconditions.checkArgument(
2481                         (slotSize > 0 && slotCount > 0) || (slotCount == 0 && slotSize == 0),
2482                         "Invalid configuration: " + slotSize + ", " + slotCount);
2483 
2484                 mLookasideSlotSize = slotSize;
2485                 mLookasideSlotCount = slotCount;
2486                 return this;
2487             }
2488 
2489             /**
2490              * Returns true if {@link #ENABLE_WRITE_AHEAD_LOGGING} flag is set
2491              * @hide
2492              */
isWriteAheadLoggingEnabled()2493             public boolean isWriteAheadLoggingEnabled() {
2494                 return (mOpenFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
2495             }
2496 
2497             /**
2498              * Sets flags to control database access mode
2499              * @param openFlags The new flags to set
2500              * @see #OPEN_READWRITE
2501              * @see #OPEN_READONLY
2502              * @see #CREATE_IF_NECESSARY
2503              * @see #NO_LOCALIZED_COLLATORS
2504              * @see #ENABLE_WRITE_AHEAD_LOGGING
2505              * @return same builder instance for chaining multiple calls into a single statement
2506              */
2507             @NonNull
setOpenFlags(@atabaseOpenFlags int openFlags)2508             public Builder setOpenFlags(@DatabaseOpenFlags int openFlags) {
2509                 mOpenFlags = openFlags;
2510                 return this;
2511             }
2512 
2513             /**
2514              * Adds flags to control database access mode
2515              *
2516              * @param openFlags The new flags to add
2517              * @return same builder instance for chaining multiple calls into a single statement
2518              */
2519             @NonNull
addOpenFlags(@atabaseOpenFlags int openFlags)2520             public Builder addOpenFlags(@DatabaseOpenFlags int openFlags) {
2521                 mOpenFlags |= openFlags;
2522                 return this;
2523             }
2524 
2525             /**
2526              * Removes database access mode flags
2527              *
2528              * @param openFlags Flags to remove
2529              * @return same builder instance for chaining multiple calls into a single statement
2530              */
2531             @NonNull
removeOpenFlags(@atabaseOpenFlags int openFlags)2532             public Builder removeOpenFlags(@DatabaseOpenFlags int openFlags) {
2533                 mOpenFlags &= ~openFlags;
2534                 return this;
2535             }
2536 
2537             /**
2538              * Sets {@link #ENABLE_WRITE_AHEAD_LOGGING} flag if {@code enabled} is {@code true},
2539              * unsets otherwise
2540              * @hide
2541              */
setWriteAheadLoggingEnabled(boolean enabled)2542             public void setWriteAheadLoggingEnabled(boolean enabled) {
2543                 if (enabled) {
2544                     addOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
2545                 } else {
2546                     removeOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
2547                 }
2548             }
2549 
2550             /**
2551              * Set an optional factory class that is called to instantiate a cursor when query
2552              * is called.
2553              *
2554              * @param cursorFactory instance
2555              * @return same builder instance for chaining multiple calls into a single statement
2556              */
2557             @NonNull
setCursorFactory(@ullable CursorFactory cursorFactory)2558             public Builder setCursorFactory(@Nullable CursorFactory cursorFactory) {
2559                 mCursorFactory = cursorFactory;
2560                 return this;
2561             }
2562 
2563 
2564             /**
2565              * Sets {@link DatabaseErrorHandler} object to handle db corruption errors
2566              */
2567             @NonNull
setErrorHandler(@ullable DatabaseErrorHandler errorHandler)2568             public Builder setErrorHandler(@Nullable DatabaseErrorHandler errorHandler) {
2569                 mErrorHandler = errorHandler;
2570                 return this;
2571             }
2572 
2573             /**
2574              * Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
2575              * before it is closed and removed from the pool.
2576              *
2577              * @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE}
2578              * to allow unlimited idle connections.
2579              */
2580             @NonNull
setIdleConnectionTimeout( @ntRangefrom = 0) long idleConnectionTimeoutMs)2581             public Builder setIdleConnectionTimeout(
2582                     @IntRange(from = 0) long idleConnectionTimeoutMs) {
2583                 Preconditions.checkArgument(idleConnectionTimeoutMs >= 0,
2584                         "idle connection timeout cannot be negative");
2585                 mIdleConnectionTimeout = idleConnectionTimeoutMs;
2586                 return this;
2587             }
2588 
2589 
2590             /**
2591              * Sets <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>
2592              * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
2593              */
2594             @NonNull
setJournalMode(@onNull String journalMode)2595             public Builder setJournalMode(@NonNull  String journalMode) {
2596                 Preconditions.checkNotNull(journalMode);
2597                 mJournalMode = journalMode;
2598                 return this;
2599             }
2600 
2601             /**
2602              * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
2603              * .
2604              * @return
2605              */
2606             @NonNull
setSynchronousMode(@onNull String syncMode)2607             public Builder setSynchronousMode(@NonNull String syncMode) {
2608                 Preconditions.checkNotNull(syncMode);
2609                 mSyncMode = syncMode;
2610                 return this;
2611             }
2612 
2613             /**
2614              * Creates an instance of {@link OpenParams} with the options that were previously set
2615              * on this builder
2616              */
2617             @NonNull
build()2618             public OpenParams build() {
2619                 return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
2620                         mLookasideSlotCount, mIdleConnectionTimeout, mJournalMode, mSyncMode);
2621             }
2622         }
2623     }
2624 
2625     /** @hide */
2626     @IntDef(flag = true, prefix = {"OPEN_", "CREATE_", "NO_", "ENABLE_"}, value = {
2627             OPEN_READWRITE,
2628             OPEN_READONLY,
2629             CREATE_IF_NECESSARY,
2630             NO_LOCALIZED_COLLATORS,
2631             ENABLE_WRITE_AHEAD_LOGGING
2632     })
2633     @Retention(RetentionPolicy.SOURCE)
2634     public @interface DatabaseOpenFlags {}
2635 
2636 }
2637 
2638