blob: caf3e9337b92f65a7c2073769a808d71f5a40191 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.database.sqlite;
18
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -070019import android.annotation.IntDef;
20import android.annotation.IntRange;
Makoto Onuki17aa1b72015-12-16 14:02:01 -080021import android.annotation.NonNull;
22import android.annotation.Nullable;
Mathew Inwood41b31942018-08-10 16:00:53 +010023import android.annotation.UnsupportedAppUsage;
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -070024import android.app.ActivityManager;
Makoto Onukiee93ad22018-10-18 16:24:13 -070025import android.app.ActivityThread;
26import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.ContentValues;
28import android.database.Cursor;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070029import android.database.DatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.database.DatabaseUtils;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070031import android.database.DefaultDatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.database.SQLException;
Vasu Noric3849202010-03-09 10:47:25 -080033import android.database.sqlite.SQLiteDebug.DbStats;
Jeff Browna7771df2012-05-07 20:06:46 -070034import android.os.CancellationSignal;
Jeff Browne5360fb2011-10-31 17:48:13 -070035import android.os.Looper;
Jeff Browna7771df2012-05-07 20:06:46 -070036import android.os.OperationCanceledException;
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -070037import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.text.TextUtils;
Makoto Onukiee93ad22018-10-18 16:24:13 -070039import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.util.EventLog;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070041import android.util.Log;
Vasu Noric3849202010-03-09 10:47:25 -080042import android.util.Pair;
Jeff Browne5360fb2011-10-31 17:48:13 -070043import android.util.Printer;
44
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -070045import com.android.internal.util.Preconditions;
46
Jeff Browne5360fb2011-10-31 17:48:13 -070047import dalvik.system.CloseGuard;
48
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.io.File;
Jeff Brown79087e42012-03-01 19:52:44 -080050import java.io.FileFilter;
Makoto Onukiee93ad22018-10-18 16:24:13 -070051import java.io.IOException;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -070052import java.lang.annotation.Retention;
53import java.lang.annotation.RetentionPolicy;
Makoto Onukiee93ad22018-10-18 16:24:13 -070054import java.nio.file.FileSystems;
55import java.nio.file.Files;
56import java.nio.file.attribute.BasicFileAttributes;
Vasu Noric3849202010-03-09 10:47:25 -080057import java.util.ArrayList;
Makoto Onukiee93ad22018-10-18 16:24:13 -070058import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import java.util.HashMap;
Jesse Wilson9b5a9352011-02-10 11:19:09 -080060import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import java.util.Locale;
62import java.util.Map;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import java.util.WeakHashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65/**
66 * Exposes methods to manage a SQLite database.
Jeff Browne5360fb2011-10-31 17:48:13 -070067 *
68 * <p>
69 * SQLiteDatabase has methods to create, delete, execute SQL commands, and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 * perform other common database management tasks.
Jeff Browne5360fb2011-10-31 17:48:13 -070071 * </p><p>
72 * See the Notepad sample application in the SDK for an example of creating
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 * and managing a database.
Jeff Browne5360fb2011-10-31 17:48:13 -070074 * </p><p>
75 * Database names must be unique within an application, not across all applications.
76 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 *
78 * <h3>Localized Collation - ORDER BY</h3>
Jeff Browne5360fb2011-10-31 17:48:13 -070079 * <p>
80 * In addition to SQLite's default <code>BINARY</code> collator, Android supplies
81 * two more, <code>LOCALIZED</code>, which changes with the system's current locale,
82 * and <code>UNICODE</code>, which is the Unicode Collation Algorithm and not tailored
83 * to the current locale.
84 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Jeff Brownbaefdfa2012-03-05 10:33:13 -080086public final class SQLiteDatabase extends SQLiteClosable {
Vasu Norifb16cbd2010-07-25 16:38:48 -070087 private static final String TAG = "SQLiteDatabase";
Jeff Browne5360fb2011-10-31 17:48:13 -070088
Jeff Hamilton082c2af2009-09-29 11:49:51 -070089 private static final int EVENT_DB_CORRUPT = 75004;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
Fyodor Kupolov535672992017-08-30 18:16:31 -070091 // By default idle connections are not closed
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -070092 private static final boolean DEBUG_CLOSE_IDLE_CONNECTIONS = SystemProperties
Fyodor Kupolov535672992017-08-30 18:16:31 -070093 .getBoolean("persist.debug.sqlite.close_idle_connections", false);
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -070094
Jeff Browne5360fb2011-10-31 17:48:13 -070095 // Stores reference to all databases opened in the current process.
96 // (The referent Object is not used at this time.)
97 // INVARIANT: Guarded by sActiveDatabases.
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -070098 private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>();
Jeff Browne5360fb2011-10-31 17:48:13 -070099
100 // Thread-local for database sessions that belong to this database.
101 // Each thread has its own database session.
102 // INVARIANT: Immutable.
Mathew Inwood41b31942018-08-10 16:00:53 +0100103 @UnsupportedAppUsage
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -0700104 private final ThreadLocal<SQLiteSession> mThreadSession = ThreadLocal
105 .withInitial(this::createSession);
Jeff Browne5360fb2011-10-31 17:48:13 -0700106
107 // The optional factory to use when creating new Cursors. May be null.
108 // INVARIANT: Immutable.
109 private final CursorFactory mCursorFactory;
110
111 // Error handler to be used when SQLite returns corruption errors.
112 // INVARIANT: Immutable.
113 private final DatabaseErrorHandler mErrorHandler;
114
115 // Shared database state lock.
116 // This lock guards all of the shared state of the database, such as its
117 // configuration, whether it is open or closed, and so on. This lock should
118 // be held for as little time as possible.
119 //
120 // The lock MUST NOT be held while attempting to acquire database connections or
121 // while executing SQL statements on behalf of the client as it can lead to deadlock.
122 //
123 // It is ok to hold the lock while reconfiguring the connection pool or dumping
124 // statistics because those operations are non-reentrant and do not try to acquire
125 // connections that might be held by other threads.
126 //
127 // Basic rule: grab the lock, access or modify global state, release the lock, then
128 // do the required SQL work.
129 private final Object mLock = new Object();
130
131 // Warns if the database is finalized without being closed properly.
132 // INVARIANT: Guarded by mLock.
133 private final CloseGuard mCloseGuardLocked = CloseGuard.get();
134
135 // The database configuration.
136 // INVARIANT: Guarded by mLock.
Mathew Inwood41b31942018-08-10 16:00:53 +0100137 @UnsupportedAppUsage
Jeff Browne5360fb2011-10-31 17:48:13 -0700138 private final SQLiteDatabaseConfiguration mConfigurationLocked;
139
140 // The connection pool for the database, null when closed.
141 // The pool itself is thread-safe, but the reference to it can only be acquired
142 // when the lock is held.
143 // INVARIANT: Guarded by mLock.
Mathew Inwood41b31942018-08-10 16:00:53 +0100144 @UnsupportedAppUsage
Jeff Browne5360fb2011-10-31 17:48:13 -0700145 private SQLiteConnectionPool mConnectionPoolLocked;
146
147 // True if the database has attached databases.
148 // INVARIANT: Guarded by mLock.
149 private boolean mHasAttachedDbsLocked;
150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700152 * When a constraint violation occurs, an immediate ROLLBACK occurs,
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800153 * thus ending the current transaction, and the command aborts with a
154 * return code of SQLITE_CONSTRAINT. If no transaction is active
155 * (other than the implied transaction that is created on every command)
Jeff Browne5360fb2011-10-31 17:48:13 -0700156 * then this algorithm works the same as ABORT.
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800157 */
158 public static final int CONFLICT_ROLLBACK = 1;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700159
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800160 /**
161 * When a constraint violation occurs,no ROLLBACK is executed
162 * so changes from prior commands within the same transaction
163 * are preserved. This is the default behavior.
164 */
165 public static final int CONFLICT_ABORT = 2;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700166
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800167 /**
168 * When a constraint violation occurs, the command aborts with a return
169 * code SQLITE_CONSTRAINT. But any changes to the database that
170 * the command made prior to encountering the constraint violation
171 * are preserved and are not backed out.
172 */
173 public static final int CONFLICT_FAIL = 3;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700174
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800175 /**
176 * When a constraint violation occurs, the one row that contains
177 * the constraint violation is not inserted or changed.
178 * But the command continues executing normally. Other rows before and
179 * after the row that contained the constraint violation continue to be
180 * inserted or updated normally. No error is returned.
181 */
182 public static final int CONFLICT_IGNORE = 4;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700183
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800184 /**
185 * When a UNIQUE constraint violation occurs, the pre-existing rows that
186 * are causing the constraint violation are removed prior to inserting
187 * or updating the current row. Thus the insert or update always occurs.
188 * The command continues executing normally. No error is returned.
189 * If a NOT NULL constraint violation occurs, the NULL value is replaced
190 * by the default value for that column. If the column has no default
191 * value, then the ABORT algorithm is used. If a CHECK constraint
192 * violation occurs then the IGNORE algorithm is used. When this conflict
193 * resolution strategy deletes rows in order to satisfy a constraint,
194 * it does not invoke delete triggers on those rows.
Jeff Browne5360fb2011-10-31 17:48:13 -0700195 * This behavior might change in a future release.
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800196 */
197 public static final int CONFLICT_REPLACE = 5;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700198
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800199 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700200 * Use the following when no conflict action is specified.
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800201 */
202 public static final int CONFLICT_NONE = 0;
Jeff Browne5360fb2011-10-31 17:48:13 -0700203
Jeff Sharkey6adc98c2018-07-12 19:47:49 -0600204 /** {@hide} */
Mathew Inwood41b31942018-08-10 16:00:53 +0100205 @UnsupportedAppUsage
Jeff Sharkey6adc98c2018-07-12 19:47:49 -0600206 public static final String[] CONFLICT_VALUES = new String[]
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800207 {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 /**
210 * Maximum Length Of A LIKE Or GLOB Pattern
211 * The pattern matching algorithm used in the default LIKE and GLOB implementation
212 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
213 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
214 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
215 * The default value of this limit is 50000. A modern workstation can evaluate
216 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
217 * The denial of service problem only comes into play when the pattern length gets
218 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
219 * are at most a few dozen bytes in length, paranoid application developers may
220 * want to reduce this parameter to something in the range of a few hundred
221 * if they know that external users are able to generate arbitrary patterns.
222 */
223 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
224
225 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700226 * Open flag: Flag for {@link #openDatabase} to open the database for reading and writing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 * If the disk is full, this may fail even before you actually write anything.
228 *
229 * {@more} Note that the value of this flag is 0, so it is the default.
230 */
231 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
232
233 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700234 * Open flag: Flag for {@link #openDatabase} to open the database for reading only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 * This is the only reliable way to open a database if the disk may be full.
236 */
237 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
238
239 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
240
241 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700242 * Open flag: Flag for {@link #openDatabase} to open the database without support for
243 * localized collators.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 *
245 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
246 * You must be consistent when using this flag to use the setting the database was
247 * created with. If this is set, {@link #setLocale} will do nothing.
248 */
249 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
250
251 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700252 * Open flag: Flag for {@link #openDatabase} to create the database file if it does not
253 * already exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 */
255 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
256
257 /**
Jeff Brown47847f32012-03-22 19:13:11 -0700258 * Open flag: Flag for {@link #openDatabase} to open the database file with
259 * write-ahead logging enabled by default. Using this flag is more efficient
260 * than calling {@link #enableWriteAheadLogging}.
261 *
262 * Write-ahead logging cannot be used with read-only databases so the value of
263 * this flag is ignored if the database is opened read-only.
264 *
265 * @see #enableWriteAheadLogging
266 */
267 public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
268
Narayan Kamathb8280432019-02-21 13:20:51 +0000269
270 // Note: The below value was only used on Android Pie.
271 // public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
272
Jeff Brown47847f32012-03-22 19:13:11 -0700273 /**
Narayan Kamathb8280432019-02-21 13:20:51 +0000274 * Open flag: Flag for {@link #openDatabase} to enable the legacy Compatibility WAL when opening
275 * database.
Fyodor Kupolov692573b2018-03-06 12:34:36 -0800276 *
277 * @hide
278 */
Narayan Kamathb8280432019-02-21 13:20:51 +0000279 public static final int ENABLE_LEGACY_COMPATIBILITY_WAL = 0x80000000;
Fyodor Kupolov692573b2018-03-06 12:34:36 -0800280
281 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700282 * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
Vasu Norib729dcc2010-09-14 11:35:49 -0700283 *
Jeff Browne5360fb2011-10-31 17:48:13 -0700284 * Each prepared-statement is between 1K - 6K, depending on the complexity of the
285 * SQL statement & schema. A large SQL cache may use a significant amount of memory.
Vasu Norie495d1f2010-01-06 16:34:19 -0800286 */
Vasu Nori90a367262010-04-12 12:49:09 -0700287 public static final int MAX_SQL_CACHE_SIZE = 100;
Vasu Norib729dcc2010-09-14 11:35:49 -0700288
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700289 private SQLiteDatabase(final String path, final int openFlags,
290 CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
Fyodor Kupolov13a4b372017-11-07 18:45:35 -0800291 int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs,
292 String journalMode, String syncMode) {
Jeff Browne5360fb2011-10-31 17:48:13 -0700293 mCursorFactory = cursorFactory;
294 mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
295 mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700296 mConfigurationLocked.lookasideSlotSize = lookasideSlotSize;
297 mConfigurationLocked.lookasideSlotCount = lookasideSlotCount;
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -0700298 // Disable lookaside allocator on low-RAM devices
299 if (ActivityManager.isLowRamDeviceStatic()) {
300 mConfigurationLocked.lookasideSlotCount = 0;
301 mConfigurationLocked.lookasideSlotSize = 0;
302 }
303 long effectiveTimeoutMs = Long.MAX_VALUE;
304 // Never close idle connections for in-memory databases
305 if (!mConfigurationLocked.isInMemoryDb()) {
306 // First, check app-specific value. Otherwise use defaults
307 // -1 in idleConnectionTimeoutMs indicates unset value
308 if (idleConnectionTimeoutMs >= 0) {
309 effectiveTimeoutMs = idleConnectionTimeoutMs;
310 } else if (DEBUG_CLOSE_IDLE_CONNECTIONS) {
311 effectiveTimeoutMs = SQLiteGlobal.getIdleConnectionTimeout();
312 }
313 }
314 mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
Fyodor Kupolov13a4b372017-11-07 18:45:35 -0800315 mConfigurationLocked.journalMode = journalMode;
316 mConfigurationLocked.syncMode = syncMode;
Narayan Kamathb8280432019-02-21 13:20:51 +0000317 if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) {
318 mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL;
Fyodor Kupolovee90c032017-12-12 11:52:57 -0800319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700321
Jeff Browne5360fb2011-10-31 17:48:13 -0700322 @Override
323 protected void finalize() throws Throwable {
324 try {
325 dispose(true);
326 } finally {
327 super.finalize();
328 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700329 }
330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 @Override
332 protected void onAllReferencesReleased() {
Jeff Browne5360fb2011-10-31 17:48:13 -0700333 dispose(false);
334 }
335
336 private void dispose(boolean finalized) {
337 final SQLiteConnectionPool pool;
338 synchronized (mLock) {
339 if (mCloseGuardLocked != null) {
340 if (finalized) {
341 mCloseGuardLocked.warnIfOpen();
342 }
343 mCloseGuardLocked.close();
344 }
345
346 pool = mConnectionPoolLocked;
347 mConnectionPoolLocked = null;
348 }
349
350 if (!finalized) {
351 synchronized (sActiveDatabases) {
352 sActiveDatabases.remove(this);
353 }
354
355 if (pool != null) {
356 pool.close();
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 }
359 }
360
361 /**
362 * Attempts to release memory that SQLite holds but does not require to
363 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700364 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 * @return the number of bytes actually released
366 */
Jeff Browne5360fb2011-10-31 17:48:13 -0700367 public static int releaseMemory() {
368 return SQLiteGlobal.releaseMemory();
369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370
371 /**
372 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
373 * around critical sections. This is pretty expensive, so if you know that your
374 * DB will only be used by a single thread then you should set this to false.
375 * The default is true.
376 * @param lockingEnabled set to true to enable locks, false otherwise
Jeff Browne5360fb2011-10-31 17:48:13 -0700377 *
378 * @deprecated This method now does nothing. Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 */
Jeff Browne5360fb2011-10-31 17:48:13 -0700380 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 public void setLockingEnabled(boolean lockingEnabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 }
383
384 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700385 * Gets a label to use when describing the database in log messages.
386 * @return The label.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 */
Jeff Browne5360fb2011-10-31 17:48:13 -0700388 String getLabel() {
389 synchronized (mLock) {
390 return mConfigurationLocked.label;
391 }
392 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393
Jeff Browne5360fb2011-10-31 17:48:13 -0700394 /**
395 * Sends a corruption message to the database error handler.
396 */
397 void onCorruption() {
398 EventLog.writeEvent(EVENT_DB_CORRUPT, getLabel());
Vasu Noriccd95442010-05-28 17:04:16 -0700399 mErrorHandler.onCorruption(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 }
401
402 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700403 * Gets the {@link SQLiteSession} that belongs to this thread for this database.
404 * Once a thread has obtained a session, it will continue to obtain the same
405 * session even after the database has been closed (although the session will not
406 * be usable). However, a thread that does not already have a session cannot
407 * obtain one after the database has been closed.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700408 *
Jeff Browne5360fb2011-10-31 17:48:13 -0700409 * The idea is that threads that have active connections to the database may still
410 * have work to complete even after the call to {@link #close}. Active database
411 * connections are not actually disposed until they are released by the threads
412 * that own them.
413 *
414 * @return The session, never null.
415 *
416 * @throws IllegalStateException if the thread does not yet have a session and
417 * the database is not open.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 */
Mathew Inwood41b31942018-08-10 16:00:53 +0100419 @UnsupportedAppUsage
Jeff Browne5360fb2011-10-31 17:48:13 -0700420 SQLiteSession getThreadSession() {
421 return mThreadSession.get(); // initialValue() throws if database closed
Vasu Nori6d970252010-10-05 10:48:49 -0700422 }
Vasu Nori16057fa2011-03-18 11:40:37 -0700423
Jeff Browne5360fb2011-10-31 17:48:13 -0700424 SQLiteSession createSession() {
425 final SQLiteConnectionPool pool;
426 synchronized (mLock) {
427 throwIfNotOpenLocked();
428 pool = mConnectionPoolLocked;
Vasu Nori6d970252010-10-05 10:48:49 -0700429 }
Jeff Browne5360fb2011-10-31 17:48:13 -0700430 return new SQLiteSession(pool);
Vasu Norid4608a32011-02-03 16:24:06 -0800431 }
432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700434 * Gets default connection flags that are appropriate for this thread, taking into
435 * account whether the thread is acting on behalf of the UI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 *
Jeff Browne5360fb2011-10-31 17:48:13 -0700437 * @param readOnly True if the connection should be read-only.
438 * @return The connection flags.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 */
Jeff Browne5360fb2011-10-31 17:48:13 -0700440 int getThreadDefaultConnectionFlags(boolean readOnly) {
441 int flags = readOnly ? SQLiteConnectionPool.CONNECTION_FLAG_READ_ONLY :
442 SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY;
443 if (isMainThread()) {
444 flags |= SQLiteConnectionPool.CONNECTION_FLAG_INTERACTIVE;
445 }
446 return flags;
Vasu Nori16057fa2011-03-18 11:40:37 -0700447 }
448
Jeff Browne5360fb2011-10-31 17:48:13 -0700449 private static boolean isMainThread() {
450 // FIXME: There should be a better way to do this.
451 // Would also be nice to have something that would work across Binder calls.
452 Looper looper = Looper.myLooper();
453 return looper != null && looper == Looper.getMainLooper();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 }
455
456 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700457 * Begins a transaction in EXCLUSIVE mode.
458 * <p>
459 * Transactions can be nested.
460 * When the outer transaction is ended all of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 * the work done in that transaction and all of the nested transactions will be committed or
462 * rolled back. The changes will be rolled back if any transaction is ended without being
463 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700464 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 * <p>Here is the standard idiom for transactions:
466 *
467 * <pre>
468 * db.beginTransaction();
469 * try {
470 * ...
471 * db.setTransactionSuccessful();
472 * } finally {
473 * db.endTransaction();
474 * }
475 * </pre>
476 */
477 public void beginTransaction() {
Vasu Nori6c354da2010-04-26 23:33:39 -0700478 beginTransaction(null /* transactionStatusCallback */, true);
479 }
480
481 /**
482 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
483 * the outer transaction is ended all of the work done in that transaction
484 * and all of the nested transactions will be committed or rolled back. The
485 * changes will be rolled back if any transaction is ended without being
486 * marked as clean (by calling setTransactionSuccessful). Otherwise they
487 * will be committed.
488 * <p>
489 * Here is the standard idiom for transactions:
490 *
491 * <pre>
492 * db.beginTransactionNonExclusive();
493 * try {
494 * ...
495 * db.setTransactionSuccessful();
496 * } finally {
497 * db.endTransaction();
498 * }
499 * </pre>
500 */
501 public void beginTransactionNonExclusive() {
502 beginTransaction(null /* transactionStatusCallback */, false);
Fred Quintanac4516a72009-09-03 12:14:06 -0700503 }
504
505 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700506 * Begins a transaction in EXCLUSIVE mode.
507 * <p>
508 * Transactions can be nested.
509 * When the outer transaction is ended all of
Fred Quintanac4516a72009-09-03 12:14:06 -0700510 * the work done in that transaction and all of the nested transactions will be committed or
511 * rolled back. The changes will be rolled back if any transaction is ended without being
512 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700513 * </p>
Fred Quintanac4516a72009-09-03 12:14:06 -0700514 * <p>Here is the standard idiom for transactions:
515 *
516 * <pre>
517 * db.beginTransactionWithListener(listener);
518 * try {
519 * ...
520 * db.setTransactionSuccessful();
521 * } finally {
522 * db.endTransaction();
523 * }
524 * </pre>
Vasu Noriccd95442010-05-28 17:04:16 -0700525 *
Fred Quintanac4516a72009-09-03 12:14:06 -0700526 * @param transactionListener listener that should be notified when the transaction begins,
527 * commits, or is rolled back, either explicitly or by a call to
528 * {@link #yieldIfContendedSafely}.
529 */
530 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700531 beginTransaction(transactionListener, true);
532 }
533
534 /**
535 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
536 * the outer transaction is ended all of the work done in that transaction
537 * and all of the nested transactions will be committed or rolled back. The
538 * changes will be rolled back if any transaction is ended without being
539 * marked as clean (by calling setTransactionSuccessful). Otherwise they
540 * will be committed.
541 * <p>
542 * Here is the standard idiom for transactions:
543 *
544 * <pre>
545 * db.beginTransactionWithListenerNonExclusive(listener);
546 * try {
547 * ...
548 * db.setTransactionSuccessful();
549 * } finally {
550 * db.endTransaction();
551 * }
552 * </pre>
553 *
554 * @param transactionListener listener that should be notified when the
555 * transaction begins, commits, or is rolled back, either
556 * explicitly or by a call to {@link #yieldIfContendedSafely}.
557 */
558 public void beginTransactionWithListenerNonExclusive(
559 SQLiteTransactionListener transactionListener) {
560 beginTransaction(transactionListener, false);
561 }
562
Mathew Inwood41b31942018-08-10 16:00:53 +0100563 @UnsupportedAppUsage
Vasu Nori6c354da2010-04-26 23:33:39 -0700564 private void beginTransaction(SQLiteTransactionListener transactionListener,
565 boolean exclusive) {
Jeff Brown03bd3022012-03-06 13:48:56 -0800566 acquireReference();
567 try {
568 getThreadSession().beginTransaction(
569 exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
570 SQLiteSession.TRANSACTION_MODE_IMMEDIATE,
571 transactionListener,
572 getThreadDefaultConnectionFlags(false /*readOnly*/), null);
573 } finally {
574 releaseReference();
575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 }
577
578 /**
579 * End a transaction. See beginTransaction for notes about how to use this and when transactions
580 * are committed and rolled back.
581 */
582 public void endTransaction() {
Jeff Brown03bd3022012-03-06 13:48:56 -0800583 acquireReference();
584 try {
585 getThreadSession().endTransaction(null);
586 } finally {
587 releaseReference();
588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 }
590
591 /**
592 * Marks the current transaction as successful. Do not do any more database work between
593 * calling this and calling endTransaction. Do as little non-database work as possible in that
594 * situation too. If any errors are encountered between this and endTransaction the transaction
595 * will still be committed.
596 *
597 * @throws IllegalStateException if the current thread is not in a transaction or the
598 * transaction is already marked as successful.
599 */
600 public void setTransactionSuccessful() {
Jeff Brown03bd3022012-03-06 13:48:56 -0800601 acquireReference();
602 try {
603 getThreadSession().setTransactionSuccessful();
604 } finally {
605 releaseReference();
606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
608
609 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700610 * Returns true if the current thread has a transaction pending.
611 *
612 * @return True if the current thread is in a transaction.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 */
614 public boolean inTransaction() {
Jeff Brown03bd3022012-03-06 13:48:56 -0800615 acquireReference();
616 try {
617 return getThreadSession().hasTransaction();
618 } finally {
619 releaseReference();
620 }
Vasu Norice38b982010-07-22 13:57:13 -0700621 }
622
623 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700624 * Returns true if the current thread is holding an active connection to the database.
Vasu Norice38b982010-07-22 13:57:13 -0700625 * <p>
Jeff Browne5360fb2011-10-31 17:48:13 -0700626 * The name of this method comes from a time when having an active connection
627 * to the database meant that the thread was holding an actual lock on the
628 * database. Nowadays, there is no longer a true "database lock" although threads
629 * may block if they cannot acquire a database connection to perform a
630 * particular operation.
631 * </p>
Vasu Norice38b982010-07-22 13:57:13 -0700632 *
Jeff Browne5360fb2011-10-31 17:48:13 -0700633 * @return True if the current thread is holding an active connection to the database.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 */
635 public boolean isDbLockedByCurrentThread() {
Jeff Brown03bd3022012-03-06 13:48:56 -0800636 acquireReference();
637 try {
638 return getThreadSession().hasConnection();
639 } finally {
640 releaseReference();
641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 }
643
644 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700645 * Always returns false.
646 * <p>
647 * There is no longer the concept of a database lock, so this method always returns false.
648 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 *
Jeff Browne5360fb2011-10-31 17:48:13 -0700650 * @return False.
651 * @deprecated Always returns false. Do not use this method.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 */
Jeff Browne5360fb2011-10-31 17:48:13 -0700653 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 public boolean isDbLockedByOtherThreads() {
Jeff Browne5360fb2011-10-31 17:48:13 -0700655 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
657
658 /**
659 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
660 * successful so far. Do not call setTransactionSuccessful before calling this. When this
661 * returns a new transaction will have been created but not marked as successful.
662 * @return true if the transaction was yielded
kopriva7364c112018-09-27 11:02:07 -0700663 * @deprecated if the db is locked more than once (because of nested transactions) then the lock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 * will not be yielded. Use yieldIfContendedSafely instead.
665 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700666 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700668 return yieldIfContendedHelper(false /* do not check yielding */,
669 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 }
671
672 /**
673 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
674 * successful so far. Do not call setTransactionSuccessful before calling this. When this
675 * returns a new transaction will have been created but not marked as successful. This assumes
676 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700677 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * @return true if the transaction was yielded
679 */
680 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700681 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Fred Quintana5c7aede2009-08-27 21:41:27 -0700684 /**
685 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
686 * successful so far. Do not call setTransactionSuccessful before calling this. When this
687 * returns a new transaction will have been created but not marked as successful. This assumes
688 * that there are no nested transactions (beginTransaction has only been called once) and will
689 * throw an exception if that is not the case.
690 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
691 * the lock was actually yielded. This will allow other background threads to make some
692 * more progress than they would if we started the transaction immediately.
693 * @return true if the transaction was yielded
694 */
695 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
696 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
697 }
698
Jeff Browne5360fb2011-10-31 17:48:13 -0700699 private boolean yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYieldDelay) {
Jeff Brown03bd3022012-03-06 13:48:56 -0800700 acquireReference();
701 try {
702 return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe, null);
703 } finally {
704 releaseReference();
705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 /**
Jeff Browne5360fb2011-10-31 17:48:13 -0700709 * Deprecated.
Vasu Nori95675132010-07-21 16:24:40 -0700710 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 */
Vasu Nori95675132010-07-21 16:24:40 -0700712 @Deprecated
713 public Map<String, String> getSyncedTables() {
714 return new HashMap<String, String>(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716
717 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 * Open the database according to the flags {@link #OPEN_READWRITE}
719 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
720 *
721 * <p>Sets the locale of the database to the the system's current locale.
722 * Call {@link #setLocale} if you would like something else.</p>
723 *
724 * @param path to database file to open and/or create
725 * @param factory an optional factory class that is called to instantiate a
726 * cursor when query is called, or null for default
727 * @param flags to control database access mode
728 * @return the newly opened database
729 * @throws SQLiteException if the database cannot be opened
730 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700731 public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
732 @DatabaseOpenFlags int flags) {
Jeff Brown47847f32012-03-22 19:13:11 -0700733 return openDatabase(path, factory, flags, null);
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700734 }
735
736 /**
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700737 * Open the database according to the specified {@link OpenParams parameters}
738 *
Fyodor Kupolov76436c02017-08-03 17:56:44 -0700739 * @param path path to database file to open and/or create.
740 * <p><strong>Important:</strong> The file should be constructed either from an absolute path or
741 * by using {@link android.content.Context#getDatabasePath(String)}.
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700742 * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}
743 * @return the newly opened database
744 * @throws SQLiteException if the database cannot be opened
745 */
Fyodor Kupolov76436c02017-08-03 17:56:44 -0700746 public static SQLiteDatabase openDatabase(@NonNull File path,
747 @NonNull OpenParams openParams) {
748 return openDatabase(path.getPath(), openParams);
749 }
750
Mathew Inwood41b31942018-08-10 16:00:53 +0100751 @UnsupportedAppUsage
Fyodor Kupolov76436c02017-08-03 17:56:44 -0700752 private static SQLiteDatabase openDatabase(@NonNull String path,
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700753 @NonNull OpenParams openParams) {
754 Preconditions.checkArgument(openParams != null, "OpenParams cannot be null");
755 SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
756 openParams.mCursorFactory, openParams.mErrorHandler,
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -0700757 openParams.mLookasideSlotSize, openParams.mLookasideSlotCount,
Fyodor Kupolov13a4b372017-11-07 18:45:35 -0800758 openParams.mIdleConnectionTimeout, openParams.mJournalMode, openParams.mSyncMode);
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700759 db.open();
760 return db;
761 }
762
763 /**
Vasu Nori74f170f2010-06-01 18:06:18 -0700764 * Open the database according to the flags {@link #OPEN_READWRITE}
765 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
766 *
767 * <p>Sets the locale of the database to the the system's current locale.
768 * Call {@link #setLocale} if you would like something else.</p>
769 *
770 * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
771 * used to handle corruption when sqlite reports database corruption.</p>
772 *
773 * @param path to database file to open and/or create
774 * @param factory an optional factory class that is called to instantiate a
775 * cursor when query is called, or null for default
776 * @param flags to control database access mode
777 * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
778 * when sqlite reports database corruption
779 * @return the newly opened database
780 * @throws SQLiteException if the database cannot be opened
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700781 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700782 public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
783 @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) {
Fyodor Kupolov13a4b372017-11-07 18:45:35 -0800784 SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1, null,
785 null);
Jeff Browne5360fb2011-10-31 17:48:13 -0700786 db.open();
787 return db;
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700788 }
789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 /**
791 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
792 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700793 public static SQLiteDatabase openOrCreateDatabase(@NonNull File file,
794 @Nullable CursorFactory factory) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 return openOrCreateDatabase(file.getPath(), factory);
796 }
797
798 /**
799 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
800 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700801 public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
802 @Nullable CursorFactory factory) {
Jeff Brown47847f32012-03-22 19:13:11 -0700803 return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
805
806 /**
Vasu Nori6c354da2010-04-26 23:33:39 -0700807 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700808 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700809 public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
810 @Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) {
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700811 return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
812 }
813
Jeff Brown559d0642012-02-29 10:19:12 -0800814 /**
Jeff Brown79087e42012-03-01 19:52:44 -0800815 * Deletes a database including its journal file and other auxiliary files
816 * that may have been created by the database engine.
817 *
818 * @param file The database file path.
819 * @return True if the database was successfully deleted.
820 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700821 public static boolean deleteDatabase(@NonNull File file) {
Makoto Onukiee93ad22018-10-18 16:24:13 -0700822 return deleteDatabase(file, /*removeCheckFile=*/ true);
823 }
824
825
826 /** @hide */
827 public static boolean deleteDatabase(@NonNull File file, boolean removeCheckFile) {
Jeff Brown79087e42012-03-01 19:52:44 -0800828 if (file == null) {
829 throw new IllegalArgumentException("file must not be null");
830 }
831
832 boolean deleted = false;
833 deleted |= file.delete();
834 deleted |= new File(file.getPath() + "-journal").delete();
835 deleted |= new File(file.getPath() + "-shm").delete();
836 deleted |= new File(file.getPath() + "-wal").delete();
837
Makoto Onukiee93ad22018-10-18 16:24:13 -0700838 // This file is not a standard SQLite file, so don't update the deleted flag.
839 new File(file.getPath() + SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX).delete();
840
Jeff Brown79087e42012-03-01 19:52:44 -0800841 File dir = file.getParentFile();
842 if (dir != null) {
843 final String prefix = file.getName() + "-mj";
Jeff Brownfce58902014-01-24 13:20:57 -0800844 File[] files = dir.listFiles(new FileFilter() {
Jeff Brown79087e42012-03-01 19:52:44 -0800845 @Override
846 public boolean accept(File candidate) {
847 return candidate.getName().startsWith(prefix);
848 }
Jeff Brownfce58902014-01-24 13:20:57 -0800849 });
850 if (files != null) {
851 for (File masterJournal : files) {
852 deleted |= masterJournal.delete();
853 }
Jeff Brown79087e42012-03-01 19:52:44 -0800854 }
855 }
856 return deleted;
857 }
858
859 /**
Jeff Brown559d0642012-02-29 10:19:12 -0800860 * Reopens the database in read-write mode.
861 * If the database is already read-write, does nothing.
862 *
863 * @throws SQLiteException if the database could not be reopened as requested, in which
864 * case it remains open in read only mode.
865 * @throws IllegalStateException if the database is not open.
866 *
867 * @see #isReadOnly()
868 * @hide
869 */
Mathew Inwood41b31942018-08-10 16:00:53 +0100870 @UnsupportedAppUsage
Jeff Brown559d0642012-02-29 10:19:12 -0800871 public void reopenReadWrite() {
872 synchronized (mLock) {
873 throwIfNotOpenLocked();
874
875 if (!isReadOnlyLocked()) {
876 return; // nothing to do
877 }
878
879 // Reopen the database in read-write mode.
880 final int oldOpenFlags = mConfigurationLocked.openFlags;
881 mConfigurationLocked.openFlags = (mConfigurationLocked.openFlags & ~OPEN_READ_MASK)
882 | OPEN_READWRITE;
883 try {
884 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
885 } catch (RuntimeException ex) {
886 mConfigurationLocked.openFlags = oldOpenFlags;
887 throw ex;
888 }
889 }
890 }
891
Jeff Browne5360fb2011-10-31 17:48:13 -0700892 private void open() {
893 try {
894 try {
895 openInner();
Makoto Onuki7a8261d2019-02-01 12:54:55 -0800896 } catch (RuntimeException ex) {
897 if (SQLiteDatabaseCorruptException.isCorruptException(ex)) {
898 Log.e(TAG, "Database corruption detected in open()", ex);
899 onCorruption();
900 openInner();
901 } else {
902 throw ex;
903 }
Jeff Browne5360fb2011-10-31 17:48:13 -0700904 }
Jeff Browne5360fb2011-10-31 17:48:13 -0700905 } catch (SQLiteException ex) {
906 Log.e(TAG, "Failed to open database '" + getLabel() + "'.", ex);
907 close();
908 throw ex;
909 }
910 }
911
912 private void openInner() {
913 synchronized (mLock) {
914 assert mConnectionPoolLocked == null;
915 mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked);
916 mCloseGuardLocked.open("close");
917 }
918
919 synchronized (sActiveDatabases) {
920 sActiveDatabases.put(this, null);
921 }
922 }
923
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700924 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 * Create a memory backed SQLite database. Its contents will be destroyed
926 * when the database is closed.
927 *
928 * <p>Sets the locale of the database to the the system's current locale.
929 * Call {@link #setLocale} if you would like something else.</p>
930 *
931 * @param factory an optional factory class that is called to instantiate a
932 * cursor when query is called
Fyodor Kupolov76436c02017-08-03 17:56:44 -0700933 * @return a SQLiteDatabase instance
934 * @throws SQLiteException if the database cannot be created
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 */
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700936 @NonNull
937 public static SQLiteDatabase create(@Nullable CursorFactory factory) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 // This is a magic string with special meaning for SQLite.
Jeff Browne5360fb2011-10-31 17:48:13 -0700939 return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
940 factory, CREATE_IF_NECESSARY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942
943 /**
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700944 * Create a memory backed SQLite database. Its contents will be destroyed
945 * when the database is closed.
946 *
947 * <p>Sets the locale of the database to the the system's current locale.
948 * Call {@link #setLocale} if you would like something else.</p>
949 * @param openParams configuration parameters that are used for opening SQLiteDatabase
Fyodor Kupolov76436c02017-08-03 17:56:44 -0700950 * @return a SQLiteDatabase instance
951 * @throws SQLException if the database cannot be created
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -0700952 */
953 @NonNull
954 public static SQLiteDatabase createInMemory(@NonNull OpenParams openParams) {
955 return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
956 openParams.toBuilder().addOpenFlags(CREATE_IF_NECESSARY).build());
957 }
958
959 /**
Mike Lockwood9d9c1be2010-07-13 19:27:52 -0400960 * Registers a CustomFunction callback as a function that can be called from
Jeff Browne5360fb2011-10-31 17:48:13 -0700961 * SQLite database triggers.
962 *
Mike Lockwood9d9c1be2010-07-13 19:27:52 -0400963 * @param name the name of the sqlite3 function
964 * @param numArgs the number of arguments for the function
965 * @param function callback to call when the function is executed
966 * @hide
967 */
968 public void addCustomFunction(String name, int numArgs, CustomFunction function) {
Jeff Browne5360fb2011-10-31 17:48:13 -0700969 // Create wrapper (also validates arguments).
970 SQLiteCustomFunction wrapper = new SQLiteCustomFunction(name, numArgs, function);
971
972 synchronized (mLock) {
973 throwIfNotOpenLocked();
Jeff Browne67ca422012-03-21 17:24:05 -0700974
Jeff Browne5360fb2011-10-31 17:48:13 -0700975 mConfigurationLocked.customFunctions.add(wrapper);
Jeff Browne67ca422012-03-21 17:24:05 -0700976 try {
977 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
978 } catch (RuntimeException ex) {
979 mConfigurationLocked.customFunctions.remove(wrapper);
980 throw ex;
981 }
Mike Lockwood9d9c1be2010-07-13 19:27:52 -0400982 }
983 }
984
Mike Lockwood9d9c1be2010-07-13 19:27:52 -0400985 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 * Gets the database version.
987 *
988 * @return the database version
989 */
990 public int getVersion() {
Vasu Noriccd95442010-05-28 17:04:16 -0700991 return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
994 /**
995 * Sets the database version.
996 *
997 * @param version the new database version
998 */
999 public void setVersion(int version) {
1000 execSQL("PRAGMA user_version = " + version);
1001 }
1002
1003 /**
1004 * Returns the maximum size the database may grow to.
1005 *
1006 * @return the new maximum database size
1007 */
1008 public long getMaximumSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001009 long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
1010 return pageCount * getPageSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
1012
1013 /**
1014 * Sets the maximum size the database will grow to. The maximum size cannot
1015 * be set below the current size.
1016 *
1017 * @param numBytes the maximum database size, in bytes
1018 * @return the new maximum database size
1019 */
1020 public long setMaximumSize(long numBytes) {
Vasu Noriccd95442010-05-28 17:04:16 -07001021 long pageSize = getPageSize();
1022 long numPages = numBytes / pageSize;
1023 // If numBytes isn't a multiple of pageSize, bump up a page
1024 if ((numBytes % pageSize) != 0) {
1025 numPages++;
Vasu Norif3cf8a42010-03-23 11:41:44 -07001026 }
Vasu Noriccd95442010-05-28 17:04:16 -07001027 long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
1028 null);
1029 return newPageCount * pageSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 }
1031
1032 /**
1033 * Returns the current database page size, in bytes.
1034 *
1035 * @return the database page size, in bytes
1036 */
1037 public long getPageSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001038 return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 }
1040
1041 /**
1042 * Sets the database page size. The page size must be a power of two. This
1043 * method does not work if any data has been written to the database file,
1044 * and must be called right after the database has been created.
1045 *
1046 * @param numBytes the database page size, in bytes
1047 */
1048 public void setPageSize(long numBytes) {
1049 execSQL("PRAGMA page_size = " + numBytes);
1050 }
1051
1052 /**
1053 * Mark this table as syncable. When an update occurs in this table the
1054 * _sync_dirty field will be set to ensure proper syncing operation.
1055 *
1056 * @param table the table to mark as syncable
1057 * @param deletedTable The deleted table that corresponds to the
1058 * syncable table
Vasu Nori95675132010-07-21 16:24:40 -07001059 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 */
Vasu Nori95675132010-07-21 16:24:40 -07001061 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 public void markTableSyncable(String table, String deletedTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064
1065 /**
1066 * Mark this table as syncable, with the _sync_dirty residing in another
1067 * table. When an update occurs in this table the _sync_dirty field of the
1068 * row in updateTable with the _id in foreignKey will be set to
1069 * ensure proper syncing operation.
1070 *
1071 * @param table an update on this table will trigger a sync time removal
1072 * @param foreignKey this is the column in table whose value is an _id in
1073 * updateTable
1074 * @param updateTable this is the table that will have its _sync_dirty
Vasu Nori95675132010-07-21 16:24:40 -07001075 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 */
Vasu Nori95675132010-07-21 16:24:40 -07001077 @Deprecated
1078 public void markTableSyncable(String table, String foreignKey, String updateTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 }
1080
1081 /**
1082 * Finds the name of the first table, which is editable.
1083 *
1084 * @param tables a list of tables
1085 * @return the first table listed
1086 */
1087 public static String findEditTable(String tables) {
1088 if (!TextUtils.isEmpty(tables)) {
1089 // find the first word terminated by either a space or a comma
1090 int spacepos = tables.indexOf(' ');
1091 int commapos = tables.indexOf(',');
1092
1093 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1094 return tables.substring(0, spacepos);
1095 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1096 return tables.substring(0, commapos);
1097 }
1098 return tables;
1099 } else {
1100 throw new IllegalStateException("Invalid tables");
1101 }
1102 }
1103
1104 /**
1105 * Compiles an SQL statement into a reusable pre-compiled statement object.
1106 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1107 * statement and fill in those values with {@link SQLiteProgram#bindString}
1108 * and {@link SQLiteProgram#bindLong} each time you want to run the
1109 * statement. Statements may not return result sets larger than 1x1.
Vasu Nori2827d6d2010-07-04 00:26:18 -07001110 *<p>
1111 * No two threads should be using the same {@link SQLiteStatement} at the same time.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 *
1113 * @param sql The raw SQL statement, may contain ? for unknown values to be
1114 * bound later.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001115 * @return A pre-compiled {@link SQLiteStatement} object. Note that
1116 * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 */
1118 public SQLiteStatement compileStatement(String sql) throws SQLException {
Jeff Brown03bd3022012-03-06 13:48:56 -08001119 acquireReference();
1120 try {
1121 return new SQLiteStatement(this, sql, null);
1122 } finally {
1123 releaseReference();
1124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 }
1126
1127 /**
1128 * Query the given URL, returning a {@link Cursor} over the result set.
1129 *
1130 * @param distinct true if you want each row to be unique, false otherwise.
1131 * @param table The table name to compile the query against.
1132 * @param columns A list of which columns to return. Passing null will
1133 * return all columns, which is discouraged to prevent reading
1134 * data from storage that isn't going to be used.
1135 * @param selection A filter declaring which rows to return, formatted as an
1136 * SQL WHERE clause (excluding the WHERE itself). Passing null
1137 * will return all rows for the given table.
1138 * @param selectionArgs You may include ?s in selection, which will be
1139 * replaced by the values from selectionArgs, in order that they
1140 * appear in the selection. The values will be bound as Strings.
1141 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1142 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1143 * will cause the rows to not be grouped.
1144 * @param having A filter declare which row groups to include in the cursor,
1145 * if row grouping is being used, formatted as an SQL HAVING
1146 * clause (excluding the HAVING itself). Passing null will cause
1147 * all row groups to be included, and is required when row
1148 * grouping is not being used.
1149 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1150 * (excluding the ORDER BY itself). Passing null will use the
1151 * default sort order, which may be unordered.
1152 * @param limit Limits the number of rows returned by the query,
1153 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001154 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1155 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 * @see Cursor
1157 */
1158 public Cursor query(boolean distinct, String table, String[] columns,
1159 String selection, String[] selectionArgs, String groupBy,
1160 String having, String orderBy, String limit) {
1161 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
Jeff Brown75ea64f2012-01-25 19:37:13 -08001162 groupBy, having, orderBy, limit, null);
1163 }
1164
1165 /**
1166 * Query the given URL, returning a {@link Cursor} over the result set.
1167 *
1168 * @param distinct true if you want each row to be unique, false otherwise.
1169 * @param table The table name to compile the query against.
1170 * @param columns A list of which columns to return. Passing null will
1171 * return all columns, which is discouraged to prevent reading
1172 * data from storage that isn't going to be used.
1173 * @param selection A filter declaring which rows to return, formatted as an
1174 * SQL WHERE clause (excluding the WHERE itself). Passing null
1175 * will return all rows for the given table.
1176 * @param selectionArgs You may include ?s in selection, which will be
1177 * replaced by the values from selectionArgs, in order that they
1178 * appear in the selection. The values will be bound as Strings.
1179 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1180 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1181 * will cause the rows to not be grouped.
1182 * @param having A filter declare which row groups to include in the cursor,
1183 * if row grouping is being used, formatted as an SQL HAVING
1184 * clause (excluding the HAVING itself). Passing null will cause
1185 * all row groups to be included, and is required when row
1186 * grouping is not being used.
1187 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1188 * (excluding the ORDER BY itself). Passing null will use the
1189 * default sort order, which may be unordered.
1190 * @param limit Limits the number of rows returned by the query,
1191 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Brown4c1241d2012-02-02 17:05:00 -08001192 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -08001193 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1194 * when the query is executed.
1195 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1196 * {@link Cursor}s are not synchronized, see the documentation for more details.
1197 * @see Cursor
1198 */
1199 public Cursor query(boolean distinct, String table, String[] columns,
1200 String selection, String[] selectionArgs, String groupBy,
Jeff Brown4c1241d2012-02-02 17:05:00 -08001201 String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
Jeff Brown75ea64f2012-01-25 19:37:13 -08001202 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
Jeff Brown4c1241d2012-02-02 17:05:00 -08001203 groupBy, having, orderBy, limit, cancellationSignal);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 }
1205
1206 /**
1207 * Query the given URL, returning a {@link Cursor} over the result set.
1208 *
1209 * @param cursorFactory the cursor factory to use, or null for the default factory
1210 * @param distinct true if you want each row to be unique, false otherwise.
1211 * @param table The table name to compile the query against.
1212 * @param columns A list of which columns to return. Passing null will
1213 * return all columns, which is discouraged to prevent reading
1214 * data from storage that isn't going to be used.
1215 * @param selection A filter declaring which rows to return, formatted as an
1216 * SQL WHERE clause (excluding the WHERE itself). Passing null
1217 * will return all rows for the given table.
1218 * @param selectionArgs You may include ?s in selection, which will be
1219 * replaced by the values from selectionArgs, in order that they
1220 * appear in the selection. The values will be bound as Strings.
1221 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1222 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1223 * will cause the rows to not be grouped.
1224 * @param having A filter declare which row groups to include in the cursor,
1225 * if row grouping is being used, formatted as an SQL HAVING
1226 * clause (excluding the HAVING itself). Passing null will cause
1227 * all row groups to be included, and is required when row
1228 * grouping is not being used.
1229 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1230 * (excluding the ORDER BY itself). Passing null will use the
1231 * default sort order, which may be unordered.
1232 * @param limit Limits the number of rows returned by the query,
1233 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001234 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1235 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 * @see Cursor
1237 */
1238 public Cursor queryWithFactory(CursorFactory cursorFactory,
1239 boolean distinct, String table, String[] columns,
1240 String selection, String[] selectionArgs, String groupBy,
1241 String having, String orderBy, String limit) {
Jeff Brown75ea64f2012-01-25 19:37:13 -08001242 return queryWithFactory(cursorFactory, distinct, table, columns, selection,
1243 selectionArgs, groupBy, having, orderBy, limit, null);
1244 }
1245
1246 /**
1247 * Query the given URL, returning a {@link Cursor} over the result set.
1248 *
1249 * @param cursorFactory the cursor factory to use, or null for the default factory
1250 * @param distinct true if you want each row to be unique, false otherwise.
1251 * @param table The table name to compile the query against.
1252 * @param columns A list of which columns to return. Passing null will
1253 * return all columns, which is discouraged to prevent reading
1254 * data from storage that isn't going to be used.
1255 * @param selection A filter declaring which rows to return, formatted as an
1256 * SQL WHERE clause (excluding the WHERE itself). Passing null
1257 * will return all rows for the given table.
1258 * @param selectionArgs You may include ?s in selection, which will be
1259 * replaced by the values from selectionArgs, in order that they
1260 * appear in the selection. The values will be bound as Strings.
1261 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1262 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1263 * will cause the rows to not be grouped.
1264 * @param having A filter declare which row groups to include in the cursor,
1265 * if row grouping is being used, formatted as an SQL HAVING
1266 * clause (excluding the HAVING itself). Passing null will cause
1267 * all row groups to be included, and is required when row
1268 * grouping is not being used.
1269 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1270 * (excluding the ORDER BY itself). Passing null will use the
1271 * default sort order, which may be unordered.
1272 * @param limit Limits the number of rows returned by the query,
1273 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Brown4c1241d2012-02-02 17:05:00 -08001274 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -08001275 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1276 * when the query is executed.
1277 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1278 * {@link Cursor}s are not synchronized, see the documentation for more details.
1279 * @see Cursor
1280 */
1281 public Cursor queryWithFactory(CursorFactory cursorFactory,
1282 boolean distinct, String table, String[] columns,
1283 String selection, String[] selectionArgs, String groupBy,
Jeff Brown4c1241d2012-02-02 17:05:00 -08001284 String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001285 acquireReference();
1286 try {
1287 String sql = SQLiteQueryBuilder.buildQueryString(
1288 distinct, table, columns, selection, groupBy, having, orderBy, limit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289
Jeff Brown03bd3022012-03-06 13:48:56 -08001290 return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
1291 findEditTable(table), cancellationSignal);
1292 } finally {
1293 releaseReference();
1294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296
1297 /**
1298 * Query the given table, returning a {@link Cursor} over the result set.
1299 *
1300 * @param table The table name to compile the query against.
1301 * @param columns A list of which columns to return. Passing null will
1302 * return all columns, which is discouraged to prevent reading
1303 * data from storage that isn't going to be used.
1304 * @param selection A filter declaring which rows to return, formatted as an
1305 * SQL WHERE clause (excluding the WHERE itself). Passing null
1306 * will return all rows for the given table.
1307 * @param selectionArgs You may include ?s in selection, which will be
1308 * replaced by the values from selectionArgs, in order that they
1309 * appear in the selection. The values will be bound as Strings.
1310 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1311 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1312 * will cause the rows to not be grouped.
1313 * @param having A filter declare which row groups to include in the cursor,
1314 * if row grouping is being used, formatted as an SQL HAVING
1315 * clause (excluding the HAVING itself). Passing null will cause
1316 * all row groups to be included, and is required when row
1317 * grouping is not being used.
1318 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1319 * (excluding the ORDER BY itself). Passing null will use the
1320 * default sort order, which may be unordered.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001321 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1322 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 * @see Cursor
1324 */
1325 public Cursor query(String table, String[] columns, String selection,
1326 String[] selectionArgs, String groupBy, String having,
1327 String orderBy) {
1328
1329 return query(false, table, columns, selection, selectionArgs, groupBy,
1330 having, orderBy, null /* limit */);
1331 }
1332
1333 /**
1334 * Query the given table, returning a {@link Cursor} over the result set.
1335 *
1336 * @param table The table name to compile the query against.
1337 * @param columns A list of which columns to return. Passing null will
1338 * return all columns, which is discouraged to prevent reading
1339 * data from storage that isn't going to be used.
1340 * @param selection A filter declaring which rows to return, formatted as an
1341 * SQL WHERE clause (excluding the WHERE itself). Passing null
1342 * will return all rows for the given table.
1343 * @param selectionArgs You may include ?s in selection, which will be
1344 * replaced by the values from selectionArgs, in order that they
1345 * appear in the selection. The values will be bound as Strings.
1346 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1347 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1348 * will cause the rows to not be grouped.
1349 * @param having A filter declare which row groups to include in the cursor,
1350 * if row grouping is being used, formatted as an SQL HAVING
1351 * clause (excluding the HAVING itself). Passing null will cause
1352 * all row groups to be included, and is required when row
1353 * grouping is not being used.
1354 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1355 * (excluding the ORDER BY itself). Passing null will use the
1356 * default sort order, which may be unordered.
1357 * @param limit Limits the number of rows returned by the query,
1358 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001359 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1360 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 * @see Cursor
1362 */
1363 public Cursor query(String table, String[] columns, String selection,
1364 String[] selectionArgs, String groupBy, String having,
1365 String orderBy, String limit) {
1366
1367 return query(false, table, columns, selection, selectionArgs, groupBy,
1368 having, orderBy, limit);
1369 }
1370
1371 /**
1372 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1373 *
1374 * @param sql the SQL query. The SQL string must not be ; terminated
1375 * @param selectionArgs You may include ?s in where clause in the query,
1376 * which will be replaced by the values from selectionArgs. The
1377 * values will be bound as Strings.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001378 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1379 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 */
1381 public Cursor rawQuery(String sql, String[] selectionArgs) {
Jeff Brown75ea64f2012-01-25 19:37:13 -08001382 return rawQueryWithFactory(null, sql, selectionArgs, null, null);
1383 }
1384
1385 /**
1386 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1387 *
1388 * @param sql the SQL query. The SQL string must not be ; terminated
1389 * @param selectionArgs You may include ?s in where clause in the query,
1390 * which will be replaced by the values from selectionArgs. The
1391 * values will be bound as Strings.
Jeff Brown4c1241d2012-02-02 17:05:00 -08001392 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -08001393 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1394 * when the query is executed.
1395 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1396 * {@link Cursor}s are not synchronized, see the documentation for more details.
1397 */
1398 public Cursor rawQuery(String sql, String[] selectionArgs,
Jeff Brown4c1241d2012-02-02 17:05:00 -08001399 CancellationSignal cancellationSignal) {
1400 return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402
1403 /**
1404 * Runs the provided SQL and returns a cursor over the result set.
1405 *
1406 * @param cursorFactory the cursor factory to use, or null for the default factory
1407 * @param sql the SQL query. The SQL string must not be ; terminated
1408 * @param selectionArgs You may include ?s in where clause in the query,
1409 * which will be replaced by the values from selectionArgs. The
1410 * values will be bound as Strings.
1411 * @param editTable the name of the first table, which is editable
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001412 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1413 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 */
1415 public Cursor rawQueryWithFactory(
1416 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1417 String editTable) {
Jeff Brown75ea64f2012-01-25 19:37:13 -08001418 return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
1419 }
1420
1421 /**
1422 * Runs the provided SQL and returns a cursor over the result set.
1423 *
1424 * @param cursorFactory the cursor factory to use, or null for the default factory
1425 * @param sql the SQL query. The SQL string must not be ; terminated
1426 * @param selectionArgs You may include ?s in where clause in the query,
1427 * which will be replaced by the values from selectionArgs. The
1428 * values will be bound as Strings.
1429 * @param editTable the name of the first table, which is editable
Jeff Brown4c1241d2012-02-02 17:05:00 -08001430 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -08001431 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1432 * when the query is executed.
1433 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1434 * {@link Cursor}s are not synchronized, see the documentation for more details.
1435 */
1436 public Cursor rawQueryWithFactory(
1437 CursorFactory cursorFactory, String sql, String[] selectionArgs,
Jeff Brown4c1241d2012-02-02 17:05:00 -08001438 String editTable, CancellationSignal cancellationSignal) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001439 acquireReference();
1440 try {
1441 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
1442 cancellationSignal);
1443 return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
1444 selectionArgs);
1445 } finally {
1446 releaseReference();
1447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449
1450 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 * Convenience method for inserting a row into the database.
1452 *
1453 * @param table the table to insert the row into
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001454 * @param nullColumnHack optional; may be <code>null</code>.
1455 * SQL doesn't allow inserting a completely empty row without
1456 * naming at least one column name. If your provided <code>values</code> is
1457 * empty, no column names are known and an empty row can't be inserted.
1458 * If not set to null, the <code>nullColumnHack</code> parameter
1459 * provides the name of nullable column name to explicitly insert a NULL into
1460 * in the case where your <code>values</code> is empty.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 * @param values this map contains the initial column values for the
1462 * row. The keys should be the column names and the values the
1463 * column values
1464 * @return the row ID of the newly inserted row, or -1 if an error occurred
1465 */
1466 public long insert(String table, String nullColumnHack, ContentValues values) {
1467 try {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001468 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 } catch (SQLException e) {
1470 Log.e(TAG, "Error inserting " + values, e);
1471 return -1;
1472 }
1473 }
1474
1475 /**
1476 * Convenience method for inserting a row into the database.
1477 *
1478 * @param table the table to insert the row into
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001479 * @param nullColumnHack optional; may be <code>null</code>.
1480 * SQL doesn't allow inserting a completely empty row without
1481 * naming at least one column name. If your provided <code>values</code> is
1482 * empty, no column names are known and an empty row can't be inserted.
1483 * If not set to null, the <code>nullColumnHack</code> parameter
1484 * provides the name of nullable column name to explicitly insert a NULL into
1485 * in the case where your <code>values</code> is empty.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 * @param values this map contains the initial column values for the
1487 * row. The keys should be the column names and the values the
1488 * column values
1489 * @throws SQLException
1490 * @return the row ID of the newly inserted row, or -1 if an error occurred
1491 */
1492 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1493 throws SQLException {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001494 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 }
1496
1497 /**
1498 * Convenience method for replacing a row in the database.
Mark Lu1e202082016-08-30 17:41:25 -07001499 * Inserts a new row if a row does not already exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 *
1501 * @param table the table in which to replace the row
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001502 * @param nullColumnHack optional; may be <code>null</code>.
1503 * SQL doesn't allow inserting a completely empty row without
1504 * naming at least one column name. If your provided <code>initialValues</code> is
1505 * empty, no column names are known and an empty row can't be inserted.
1506 * If not set to null, the <code>nullColumnHack</code> parameter
1507 * provides the name of nullable column name to explicitly insert a NULL into
1508 * in the case where your <code>initialValues</code> is empty.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 * @param initialValues this map contains the initial column values for
Mark Lu1e202082016-08-30 17:41:25 -07001510 * the row. The keys should be the column names and the values the column values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 * @return the row ID of the newly inserted row, or -1 if an error occurred
1512 */
1513 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1514 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001515 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001516 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 } catch (SQLException e) {
1518 Log.e(TAG, "Error inserting " + initialValues, e);
1519 return -1;
1520 }
1521 }
1522
1523 /**
1524 * Convenience method for replacing a row in the database.
Mark Lu1e202082016-08-30 17:41:25 -07001525 * Inserts a new row if a row does not already exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 *
1527 * @param table the table in which to replace the row
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001528 * @param nullColumnHack optional; may be <code>null</code>.
1529 * SQL doesn't allow inserting a completely empty row without
1530 * naming at least one column name. If your provided <code>initialValues</code> is
1531 * empty, no column names are known and an empty row can't be inserted.
1532 * If not set to null, the <code>nullColumnHack</code> parameter
1533 * provides the name of nullable column name to explicitly insert a NULL into
1534 * in the case where your <code>initialValues</code> is empty.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 * @param initialValues this map contains the initial column values for
Mark Lu1e202082016-08-30 17:41:25 -07001536 * the row. The keys should be the column names and the values the column values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 * @throws SQLException
1538 * @return the row ID of the newly inserted row, or -1 if an error occurred
1539 */
1540 public long replaceOrThrow(String table, String nullColumnHack,
1541 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001542 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001543 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 }
1545
1546 /**
1547 * General method for inserting a row into the database.
1548 *
1549 * @param table the table to insert the row into
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001550 * @param nullColumnHack optional; may be <code>null</code>.
1551 * SQL doesn't allow inserting a completely empty row without
1552 * naming at least one column name. If your provided <code>initialValues</code> is
1553 * empty, no column names are known and an empty row can't be inserted.
1554 * If not set to null, the <code>nullColumnHack</code> parameter
1555 * provides the name of nullable column name to explicitly insert a NULL into
1556 * in the case where your <code>initialValues</code> is empty.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 * @param initialValues this map contains the initial column values for the
1558 * row. The keys should be the column names and the values the
1559 * column values
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001560 * @param conflictAlgorithm for insert conflict resolver
Steve Pomeroyc240b602013-03-14 00:42:10 -04001561 * @return the row ID of the newly inserted row OR <code>-1</code> if either the
1562 * input parameter <code>conflictAlgorithm</code> = {@link #CONFLICT_IGNORE}
1563 * or an error occurred.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 */
1565 public long insertWithOnConflict(String table, String nullColumnHack,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001566 ContentValues initialValues, int conflictAlgorithm) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001567 acquireReference();
1568 try {
1569 StringBuilder sql = new StringBuilder();
1570 sql.append("INSERT");
1571 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
1572 sql.append(" INTO ");
1573 sql.append(table);
1574 sql.append('(');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575
Jeff Brown03bd3022012-03-06 13:48:56 -08001576 Object[] bindArgs = null;
Mike Tsaoc74ee2f2017-03-24 14:56:34 -07001577 int size = (initialValues != null && !initialValues.isEmpty())
Jeff Brown03bd3022012-03-06 13:48:56 -08001578 ? initialValues.size() : 0;
1579 if (size > 0) {
1580 bindArgs = new Object[size];
1581 int i = 0;
1582 for (String colName : initialValues.keySet()) {
1583 sql.append((i > 0) ? "," : "");
1584 sql.append(colName);
1585 bindArgs[i++] = initialValues.get(colName);
1586 }
1587 sql.append(')');
1588 sql.append(" VALUES (");
1589 for (i = 0; i < size; i++) {
1590 sql.append((i > 0) ? ",?" : "?");
1591 }
1592 } else {
1593 sql.append(nullColumnHack + ") VALUES (NULL");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 sql.append(')');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596
Jeff Brown03bd3022012-03-06 13:48:56 -08001597 SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
1598 try {
1599 return statement.executeInsert();
1600 } finally {
1601 statement.close();
1602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 } finally {
Jeff Brown03bd3022012-03-06 13:48:56 -08001604 releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606 }
1607
1608 /**
1609 * Convenience method for deleting rows in the database.
1610 *
1611 * @param table the table to delete from
1612 * @param whereClause the optional WHERE clause to apply when deleting.
1613 * Passing null will delete all rows.
Tim Roesfd020742013-01-22 23:12:11 +01001614 * @param whereArgs You may include ?s in the where clause, which
1615 * will be replaced by the values from whereArgs. The values
1616 * will be bound as Strings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 * @return the number of rows affected if a whereClause is passed in, 0
1618 * otherwise. To remove all rows and get a count pass "1" as the
1619 * whereClause.
1620 */
1621 public int delete(String table, String whereClause, String[] whereArgs) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001622 acquireReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 try {
Jeff Brown03bd3022012-03-06 13:48:56 -08001624 SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
1625 (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
1626 try {
1627 return statement.executeUpdateDelete();
1628 } finally {
1629 statement.close();
1630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 } finally {
Jeff Brown03bd3022012-03-06 13:48:56 -08001632 releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 }
1634 }
1635
1636 /**
1637 * Convenience method for updating rows in the database.
1638 *
1639 * @param table the table to update in
1640 * @param values a map from column names to new column values. null is a
1641 * valid value that will be translated to NULL.
1642 * @param whereClause the optional WHERE clause to apply when updating.
1643 * Passing null will update all rows.
Tim Roesfd020742013-01-22 23:12:11 +01001644 * @param whereArgs You may include ?s in the where clause, which
1645 * will be replaced by the values from whereArgs. The values
1646 * will be bound as Strings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 * @return the number of rows affected
1648 */
1649 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001650 return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 /**
1654 * Convenience method for updating rows in the database.
1655 *
1656 * @param table the table to update in
1657 * @param values a map from column names to new column values. null is a
1658 * valid value that will be translated to NULL.
1659 * @param whereClause the optional WHERE clause to apply when updating.
1660 * Passing null will update all rows.
Tim Roesfd020742013-01-22 23:12:11 +01001661 * @param whereArgs You may include ?s in the where clause, which
1662 * will be replaced by the values from whereArgs. The values
1663 * will be bound as Strings.
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001664 * @param conflictAlgorithm for update conflict resolver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 * @return the number of rows affected
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001667 public int updateWithOnConflict(String table, ContentValues values,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001668 String whereClause, String[] whereArgs, int conflictAlgorithm) {
Mike Tsaoc74ee2f2017-03-24 14:56:34 -07001669 if (values == null || values.isEmpty()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 throw new IllegalArgumentException("Empty values");
1671 }
1672
Jeff Brown03bd3022012-03-06 13:48:56 -08001673 acquireReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 try {
Jeff Brown03bd3022012-03-06 13:48:56 -08001675 StringBuilder sql = new StringBuilder(120);
1676 sql.append("UPDATE ");
1677 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
1678 sql.append(table);
1679 sql.append(" SET ");
1680
1681 // move all bind args to one array
1682 int setValuesSize = values.size();
1683 int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
1684 Object[] bindArgs = new Object[bindArgsSize];
1685 int i = 0;
1686 for (String colName : values.keySet()) {
1687 sql.append((i > 0) ? "," : "");
1688 sql.append(colName);
1689 bindArgs[i++] = values.get(colName);
1690 sql.append("=?");
1691 }
1692 if (whereArgs != null) {
1693 for (i = setValuesSize; i < bindArgsSize; i++) {
1694 bindArgs[i] = whereArgs[i - setValuesSize];
1695 }
1696 }
1697 if (!TextUtils.isEmpty(whereClause)) {
1698 sql.append(" WHERE ");
1699 sql.append(whereClause);
1700 }
1701
1702 SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
1703 try {
1704 return statement.executeUpdateDelete();
1705 } finally {
1706 statement.close();
1707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 } finally {
Jeff Brown03bd3022012-03-06 13:48:56 -08001709 releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
1711 }
1712
1713 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001714 * Execute a single SQL statement that is NOT a SELECT
1715 * or any other SQL statement that returns data.
1716 * <p>
Vasu Norice38b982010-07-22 13:57:13 -07001717 * It has no means to return any data (such as the number of affected rows).
Vasu Noriccd95442010-05-28 17:04:16 -07001718 * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
1719 * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
1720 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001721 * <p>
1722 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1723 * automatically managed by this class. So, do not set journal_mode
1724 * using "PRAGMA journal_mode'<value>" statement if your app is using
1725 * {@link #enableWriteAheadLogging()}
1726 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 *
Vasu Noriccd95442010-05-28 17:04:16 -07001728 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1729 * not supported.
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001730 * @throws SQLException if the SQL string is invalid
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 */
Vasu Norib83cb7c2010-09-14 13:36:01 -07001732 public void execSQL(String sql) throws SQLException {
Vasu Nori16057fa2011-03-18 11:40:37 -07001733 executeSql(sql, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735
1736 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001737 * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
1738 * <p>
1739 * For INSERT statements, use any of the following instead.
1740 * <ul>
1741 * <li>{@link #insert(String, String, ContentValues)}</li>
1742 * <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
1743 * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
1744 * </ul>
1745 * <p>
1746 * For UPDATE statements, use any of the following instead.
1747 * <ul>
1748 * <li>{@link #update(String, ContentValues, String, String[])}</li>
1749 * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
1750 * </ul>
1751 * <p>
1752 * For DELETE statements, use any of the following instead.
1753 * <ul>
1754 * <li>{@link #delete(String, String, String[])}</li>
1755 * </ul>
1756 * <p>
1757 * For example, the following are good candidates for using this method:
1758 * <ul>
1759 * <li>ALTER TABLE</li>
1760 * <li>CREATE or DROP table / trigger / view / index / virtual table</li>
1761 * <li>REINDEX</li>
1762 * <li>RELEASE</li>
1763 * <li>SAVEPOINT</li>
1764 * <li>PRAGMA that returns no data</li>
1765 * </ul>
1766 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001767 * <p>
1768 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1769 * automatically managed by this class. So, do not set journal_mode
1770 * using "PRAGMA journal_mode'<value>" statement if your app is using
1771 * {@link #enableWriteAheadLogging()}
1772 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 *
Vasu Noriccd95442010-05-28 17:04:16 -07001774 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1775 * not supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
Brad Fitzpatrick69ea4e12011-01-05 11:13:40 -08001777 * @throws SQLException if the SQL string is invalid
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 */
Vasu Norib83cb7c2010-09-14 13:36:01 -07001779 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 if (bindArgs == null) {
1781 throw new IllegalArgumentException("Empty bindArgs");
1782 }
Vasu Norib83cb7c2010-09-14 13:36:01 -07001783 executeSql(sql, bindArgs);
Vasu Norice38b982010-07-22 13:57:13 -07001784 }
1785
Jeff Sharkey6adc98c2018-07-12 19:47:49 -06001786 /** {@hide} */
1787 public int executeSql(String sql, Object[] bindArgs) throws SQLException {
Jeff Brown03bd3022012-03-06 13:48:56 -08001788 acquireReference();
1789 try {
Fyodor Kupolov25095c02017-11-17 14:02:10 -08001790 final int statementType = DatabaseUtils.getSqlStatementType(sql);
1791 if (statementType == DatabaseUtils.STATEMENT_ATTACH) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001792 boolean disableWal = false;
1793 synchronized (mLock) {
1794 if (!mHasAttachedDbsLocked) {
1795 mHasAttachedDbsLocked = true;
1796 disableWal = true;
Fyodor Kupolovfd9c4a52017-07-13 15:36:57 -07001797 mConnectionPoolLocked.disableIdleConnectionHandler();
Jeff Brown03bd3022012-03-06 13:48:56 -08001798 }
1799 }
1800 if (disableWal) {
1801 disableWriteAheadLogging();
Jeff Browne5360fb2011-10-31 17:48:13 -07001802 }
1803 }
Jeff Browne5360fb2011-10-31 17:48:13 -07001804
Fyodor Kupolov25095c02017-11-17 14:02:10 -08001805 try (SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs)) {
Jeff Brown03bd3022012-03-06 13:48:56 -08001806 return statement.executeUpdateDelete();
1807 } finally {
Fyodor Kupolov25095c02017-11-17 14:02:10 -08001808 // If schema was updated, close non-primary connections, otherwise they might
1809 // have outdated schema information
1810 if (statementType == DatabaseUtils.STATEMENT_DDL) {
1811 mConnectionPoolLocked.closeAvailableNonPrimaryConnectionsAndLogExceptions();
1812 }
Jeff Brown03bd3022012-03-06 13:48:56 -08001813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 } finally {
Jeff Brown03bd3022012-03-06 13:48:56 -08001815 releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 }
1818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 /**
Makoto Onuki17aa1b72015-12-16 14:02:01 -08001820 * Verifies that a SQL SELECT statement is valid by compiling it.
1821 * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
1822 *
1823 * @param sql SQL to be validated
1824 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
1825 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
1826 * when the query is executed.
1827 * @throws SQLiteException if {@code sql} is invalid
1828 */
1829 public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal) {
1830 getThreadSession().prepare(sql,
1831 getThreadDefaultConnectionFlags(/* readOnly =*/ true), cancellationSignal, null);
1832 }
1833
1834 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07001835 * Returns true if the database is opened as read only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 *
Jeff Browne5360fb2011-10-31 17:48:13 -07001837 * @return True if database is opened as read only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 */
1839 public boolean isReadOnly() {
Jeff Browne5360fb2011-10-31 17:48:13 -07001840 synchronized (mLock) {
1841 return isReadOnlyLocked();
1842 }
1843 }
1844
1845 private boolean isReadOnlyLocked() {
1846 return (mConfigurationLocked.openFlags & OPEN_READ_MASK) == OPEN_READONLY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 }
1848
1849 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07001850 * Returns true if the database is in-memory db.
1851 *
1852 * @return True if the database is in-memory.
1853 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 */
Jeff Browne5360fb2011-10-31 17:48:13 -07001855 public boolean isInMemoryDatabase() {
1856 synchronized (mLock) {
1857 return mConfigurationLocked.isInMemoryDb();
1858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 }
1860
Jeff Browne5360fb2011-10-31 17:48:13 -07001861 /**
1862 * Returns true if the database is currently open.
1863 *
1864 * @return True if the database is currently open (has not been closed).
1865 */
1866 public boolean isOpen() {
1867 synchronized (mLock) {
1868 return mConnectionPoolLocked != null;
1869 }
1870 }
1871
1872 /**
1873 * Returns true if the new version code is greater than the current database version.
1874 *
1875 * @param newVersion The new version code.
Mark Lu1e202082016-08-30 17:41:25 -07001876 * @return True if the new version code is greater than the current database version.
Jeff Browne5360fb2011-10-31 17:48:13 -07001877 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 public boolean needUpgrade(int newVersion) {
1879 return newVersion > getVersion();
1880 }
1881
1882 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07001883 * Gets the path to the database file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 *
Jeff Browne5360fb2011-10-31 17:48:13 -07001885 * @return The path to the database file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 */
1887 public final String getPath() {
Jeff Browne5360fb2011-10-31 17:48:13 -07001888 synchronized (mLock) {
1889 return mConfigurationLocked.path;
Christopher Tatead9e8b12011-10-05 17:49:26 -07001890 }
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001891 }
1892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 /**
1894 * Sets the locale for this database. Does nothing if this database has
Jeff Brown1d9f7422012-03-15 14:32:32 -07001895 * the {@link #NO_LOCALIZED_COLLATORS} flag set or was opened read only.
Jeff Browne5360fb2011-10-31 17:48:13 -07001896 *
1897 * @param locale The new locale.
1898 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 * @throws SQLException if the locale could not be set. The most common reason
1900 * for this is that there is no collator available for the locale you requested.
1901 * In this case the database remains unchanged.
1902 */
1903 public void setLocale(Locale locale) {
Jeff Browne5360fb2011-10-31 17:48:13 -07001904 if (locale == null) {
1905 throw new IllegalArgumentException("locale must not be null.");
Jesse Wilsondfe515e2011-02-10 19:06:09 -08001906 }
Vasu Norib729dcc2010-09-14 11:35:49 -07001907
Jeff Browne5360fb2011-10-31 17:48:13 -07001908 synchronized (mLock) {
1909 throwIfNotOpenLocked();
Jeff Browne67ca422012-03-21 17:24:05 -07001910
1911 final Locale oldLocale = mConfigurationLocked.locale;
Jeff Browne5360fb2011-10-31 17:48:13 -07001912 mConfigurationLocked.locale = locale;
Jeff Browne67ca422012-03-21 17:24:05 -07001913 try {
1914 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1915 } catch (RuntimeException ex) {
1916 mConfigurationLocked.locale = oldLocale;
1917 throw ex;
1918 }
Vasu Norib729dcc2010-09-14 11:35:49 -07001919 }
Vasu Norib729dcc2010-09-14 11:35:49 -07001920 }
1921
Vasu Norie495d1f2010-01-06 16:34:19 -08001922 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001923 * Sets the maximum size of the prepared-statement cache for this database.
Vasu Norie495d1f2010-01-06 16:34:19 -08001924 * (size of the cache = number of compiled-sql-statements stored in the cache).
Vasu Noriccd95442010-05-28 17:04:16 -07001925 *<p>
Vasu Norib729dcc2010-09-14 11:35:49 -07001926 * Maximum cache size can ONLY be increased from its current size (default = 10).
Vasu Noriccd95442010-05-28 17:04:16 -07001927 * If this method is called with smaller size than the current maximum value,
1928 * then IllegalStateException is thrown.
Vasu Norib729dcc2010-09-14 11:35:49 -07001929 *<p>
1930 * This method is thread-safe.
Vasu Norie495d1f2010-01-06 16:34:19 -08001931 *
Vasu Nori90a367262010-04-12 12:49:09 -07001932 * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
Jeff Browne5360fb2011-10-31 17:48:13 -07001933 * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE}.
Vasu Norie495d1f2010-01-06 16:34:19 -08001934 */
Vasu Nori54025902010-09-14 12:14:26 -07001935 public void setMaxSqlCacheSize(int cacheSize) {
Jeff Browne5360fb2011-10-31 17:48:13 -07001936 if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
1937 throw new IllegalStateException(
1938 "expected value between 0 and " + MAX_SQL_CACHE_SIZE);
Vasu Nori587423a2010-09-27 18:18:34 -07001939 }
Vasu Nori587423a2010-09-27 18:18:34 -07001940
Jeff Browne5360fb2011-10-31 17:48:13 -07001941 synchronized (mLock) {
1942 throwIfNotOpenLocked();
Jeff Browne67ca422012-03-21 17:24:05 -07001943
1944 final int oldMaxSqlCacheSize = mConfigurationLocked.maxSqlCacheSize;
Jeff Browne5360fb2011-10-31 17:48:13 -07001945 mConfigurationLocked.maxSqlCacheSize = cacheSize;
Jeff Browne67ca422012-03-21 17:24:05 -07001946 try {
1947 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1948 } catch (RuntimeException ex) {
1949 mConfigurationLocked.maxSqlCacheSize = oldMaxSqlCacheSize;
1950 throw ex;
1951 }
Jesse Wilsondfe515e2011-02-10 19:06:09 -08001952 }
1953 }
1954
Vasu Nori6c354da2010-04-26 23:33:39 -07001955 /**
Jeff Brown96496ad2012-03-23 14:38:06 -07001956 * Sets whether foreign key constraints are enabled for the database.
1957 * <p>
1958 * By default, foreign key constraints are not enforced by the database.
1959 * This method allows an application to enable foreign key constraints.
1960 * It must be called each time the database is opened to ensure that foreign
1961 * key constraints are enabled for the session.
1962 * </p><p>
1963 * A good time to call this method is right after calling {@link #openOrCreateDatabase}
1964 * or in the {@link SQLiteOpenHelper#onConfigure} callback.
1965 * </p><p>
1966 * When foreign key constraints are disabled, the database does not check whether
1967 * changes to the database will violate foreign key constraints. Likewise, when
1968 * foreign key constraints are disabled, the database will not execute cascade
1969 * delete or update triggers. As a result, it is possible for the database
1970 * state to become inconsistent. To perform a database integrity check,
1971 * call {@link #isDatabaseIntegrityOk}.
1972 * </p><p>
1973 * This method must not be called while a transaction is in progress.
1974 * </p><p>
1975 * See also <a href="http://sqlite.org/foreignkeys.html">SQLite Foreign Key Constraints</a>
1976 * for more details about foreign key constraint support.
1977 * </p>
1978 *
1979 * @param enable True to enable foreign key constraints, false to disable them.
1980 *
1981 * @throws IllegalStateException if the are transactions is in progress
1982 * when this method is called.
1983 */
1984 public void setForeignKeyConstraintsEnabled(boolean enable) {
1985 synchronized (mLock) {
1986 throwIfNotOpenLocked();
1987
1988 if (mConfigurationLocked.foreignKeyConstraintsEnabled == enable) {
1989 return;
1990 }
1991
1992 mConfigurationLocked.foreignKeyConstraintsEnabled = enable;
1993 try {
1994 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
1995 } catch (RuntimeException ex) {
1996 mConfigurationLocked.foreignKeyConstraintsEnabled = !enable;
1997 throw ex;
1998 }
1999 }
2000 }
2001
2002 /**
Jeff Brown47847f32012-03-22 19:13:11 -07002003 * This method enables parallel execution of queries from multiple threads on the
2004 * same database. It does this by opening multiple connections to the database
2005 * and using a different database connection for each query. The database
2006 * journal mode is also changed to enable writes to proceed concurrently with reads.
Vasu Nori6c354da2010-04-26 23:33:39 -07002007 * <p>
Jeff Brown47847f32012-03-22 19:13:11 -07002008 * When write-ahead logging is not enabled (the default), it is not possible for
2009 * reads and writes to occur on the database at the same time. Before modifying the
2010 * database, the writer implicitly acquires an exclusive lock on the database which
2011 * prevents readers from accessing the database until the write is completed.
2012 * </p><p>
2013 * In contrast, when write-ahead logging is enabled (by calling this method), write
2014 * operations occur in a separate log file which allows reads to proceed concurrently.
2015 * While a write is in progress, readers on other threads will perceive the state
2016 * of the database as it was before the write began. When the write completes, readers
2017 * on other threads will then perceive the new state of the database.
2018 * </p><p>
2019 * It is a good idea to enable write-ahead logging whenever a database will be
2020 * concurrently accessed and modified by multiple threads at the same time.
2021 * However, write-ahead logging uses significantly more memory than ordinary
2022 * journaling because there are multiple connections to the same database.
2023 * So if a database will only be used by a single thread, or if optimizing
2024 * concurrency is not very important, then write-ahead logging should be disabled.
2025 * </p><p>
2026 * After calling this method, execution of queries in parallel is enabled as long as
2027 * the database remains open. To disable execution of queries in parallel, either
2028 * call {@link #disableWriteAheadLogging} or close the database and reopen it.
2029 * </p><p>
2030 * The maximum number of connections used to execute queries in parallel is
Vasu Nori6c354da2010-04-26 23:33:39 -07002031 * dependent upon the device memory and possibly other properties.
Jeff Brown47847f32012-03-22 19:13:11 -07002032 * </p><p>
Vasu Nori6c354da2010-04-26 23:33:39 -07002033 * If a query is part of a transaction, then it is executed on the same database handle the
2034 * transaction was begun.
Jeff Brown47847f32012-03-22 19:13:11 -07002035 * </p><p>
Vasu Nori6c354da2010-04-26 23:33:39 -07002036 * Writers should use {@link #beginTransactionNonExclusive()} or
2037 * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
Jeff Brown47847f32012-03-22 19:13:11 -07002038 * to start a transaction. Non-exclusive mode allows database file to be in readable
2039 * by other threads executing queries.
2040 * </p><p>
2041 * If the database has any attached databases, then execution of queries in parallel is NOT
2042 * possible. Likewise, write-ahead logging is not supported for read-only databases
2043 * or memory databases. In such cases, {@link #enableWriteAheadLogging} returns false.
2044 * </p><p>
2045 * The best way to enable write-ahead logging is to pass the
2046 * {@link #ENABLE_WRITE_AHEAD_LOGGING} flag to {@link #openDatabase}. This is
2047 * more efficient than calling {@link #enableWriteAheadLogging}.
2048 * <code><pre>
2049 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2050 * SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
2051 * myDatabaseErrorHandler);
Jeff Brown47847f32012-03-22 19:13:11 -07002052 * </pre></code>
2053 * </p><p>
2054 * Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging}
2055 * after opening the database.
2056 * <code><pre>
2057 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2058 * SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);
2059 * db.enableWriteAheadLogging();
2060 * </pre></code>
2061 * </p><p>
2062 * See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for
2063 * more details about how write-ahead logging works.
Vasu Nori6c354da2010-04-26 23:33:39 -07002064 * </p>
2065 *
Jeff Brown47847f32012-03-22 19:13:11 -07002066 * @return True if write-ahead logging is enabled.
Jeff Browne67ca422012-03-21 17:24:05 -07002067 *
Jean-Baptiste Queru73644772012-03-21 19:24:32 -07002068 * @throws IllegalStateException if there are transactions in progress at the
Jeff Browne67ca422012-03-21 17:24:05 -07002069 * time this method is called. WAL mode can only be changed when there are no
2070 * transactions in progress.
Jeff Brown47847f32012-03-22 19:13:11 -07002071 *
2072 * @see #ENABLE_WRITE_AHEAD_LOGGING
2073 * @see #disableWriteAheadLogging
Vasu Nori6c354da2010-04-26 23:33:39 -07002074 */
Vasu Noriffe06122010-09-27 12:32:57 -07002075 public boolean enableWriteAheadLogging() {
Jeff Browne5360fb2011-10-31 17:48:13 -07002076 synchronized (mLock) {
2077 throwIfNotOpenLocked();
2078
Jeff Brown47847f32012-03-22 19:13:11 -07002079 if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
Paul Westbrookdae6d372011-02-17 10:59:56 -08002080 return true;
2081 }
Jeff Browne5360fb2011-10-31 17:48:13 -07002082
2083 if (isReadOnlyLocked()) {
2084 // WAL doesn't make sense for readonly-databases.
2085 // TODO: True, but connection pooling does still make sense...
2086 return false;
2087 }
2088
2089 if (mConfigurationLocked.isInMemoryDb()) {
Paul Westbrookdae6d372011-02-17 10:59:56 -08002090 Log.i(TAG, "can't enable WAL for memory databases.");
2091 return false;
2092 }
2093
2094 // make sure this database has NO attached databases because sqlite's write-ahead-logging
2095 // doesn't work for databases with attached databases
Jeff Browne5360fb2011-10-31 17:48:13 -07002096 if (mHasAttachedDbsLocked) {
Paul Westbrookdae6d372011-02-17 10:59:56 -08002097 if (Log.isLoggable(TAG, Log.DEBUG)) {
Jeff Browne5360fb2011-10-31 17:48:13 -07002098 Log.d(TAG, "this database: " + mConfigurationLocked.label
2099 + " has attached databases. can't enable WAL.");
Paul Westbrookdae6d372011-02-17 10:59:56 -08002100 }
2101 return false;
2102 }
Jeff Browne5360fb2011-10-31 17:48:13 -07002103
Jeff Brown47847f32012-03-22 19:13:11 -07002104 mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
Jeff Browne67ca422012-03-21 17:24:05 -07002105 try {
2106 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
2107 } catch (RuntimeException ex) {
Jeff Brown47847f32012-03-22 19:13:11 -07002108 mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
Jeff Browne67ca422012-03-21 17:24:05 -07002109 throw ex;
2110 }
Paul Westbrookdae6d372011-02-17 10:59:56 -08002111 }
Jeff Browne5360fb2011-10-31 17:48:13 -07002112 return true;
Vasu Nori6c354da2010-04-26 23:33:39 -07002113 }
2114
Vasu Nori2827d6d2010-07-04 00:26:18 -07002115 /**
Vasu Nori7b04c412010-07-20 10:31:21 -07002116 * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
Jeff Browne67ca422012-03-21 17:24:05 -07002117 *
Jean-Baptiste Queru73644772012-03-21 19:24:32 -07002118 * @throws IllegalStateException if there are transactions in progress at the
Jeff Browne67ca422012-03-21 17:24:05 -07002119 * time this method is called. WAL mode can only be changed when there are no
2120 * transactions in progress.
Jeff Brown47847f32012-03-22 19:13:11 -07002121 *
2122 * @see #enableWriteAheadLogging
Vasu Nori2827d6d2010-07-04 00:26:18 -07002123 */
Vasu Nori7b04c412010-07-20 10:31:21 -07002124 public void disableWriteAheadLogging() {
Jeff Browne5360fb2011-10-31 17:48:13 -07002125 synchronized (mLock) {
2126 throwIfNotOpenLocked();
2127
Fyodor Kupolov5bd43ad2017-10-25 16:09:35 -07002128 final int oldFlags = mConfigurationLocked.openFlags;
Narayan Kamathb8280432019-02-21 13:20:51 +00002129 final boolean walEnabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
2130 final boolean compatibilityWalEnabled =
2131 (oldFlags & ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
2132 // WAL was never enabled for this database, so there's nothing left to do.
2133 if (!walEnabled && !compatibilityWalEnabled) {
Jeff Browne5360fb2011-10-31 17:48:13 -07002134 return;
Paul Westbrookdae6d372011-02-17 10:59:56 -08002135 }
Vasu Nori8d111032010-06-22 18:34:21 -07002136
Narayan Kamathb8280432019-02-21 13:20:51 +00002137 // If an app explicitly disables WAL, it takes priority over any directive
2138 // to use the legacy "compatibility WAL" mode.
Jeff Brown47847f32012-03-22 19:13:11 -07002139 mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
Narayan Kamathb8280432019-02-21 13:20:51 +00002140 mConfigurationLocked.openFlags &= ~ENABLE_LEGACY_COMPATIBILITY_WAL;
Fyodor Kupolov5bd43ad2017-10-25 16:09:35 -07002141
Jeff Browne67ca422012-03-21 17:24:05 -07002142 try {
2143 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
2144 } catch (RuntimeException ex) {
Fyodor Kupolov5bd43ad2017-10-25 16:09:35 -07002145 mConfigurationLocked.openFlags = oldFlags;
Jeff Browne67ca422012-03-21 17:24:05 -07002146 throw ex;
2147 }
Vasu Nori65a88832010-07-16 15:14:08 -07002148 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002149 }
2150
Vasu Norif3cf8a42010-03-23 11:41:44 -07002151 /**
Jeff Brown47847f32012-03-22 19:13:11 -07002152 * Returns true if write-ahead logging has been enabled for this database.
2153 *
2154 * @return True if write-ahead logging has been enabled for this database.
2155 *
2156 * @see #enableWriteAheadLogging
2157 * @see #ENABLE_WRITE_AHEAD_LOGGING
2158 */
2159 public boolean isWriteAheadLoggingEnabled() {
2160 synchronized (mLock) {
2161 throwIfNotOpenLocked();
2162
2163 return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
2164 }
2165 }
2166
2167 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07002168 * Collect statistics about all open databases in the current process.
2169 * Used by bug report.
Vasu Norif3cf8a42010-03-23 11:41:44 -07002170 */
Jeff Browne5360fb2011-10-31 17:48:13 -07002171 static ArrayList<DbStats> getDbStats() {
Vasu Noric3849202010-03-09 10:47:25 -08002172 ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
Jeff Browne5360fb2011-10-31 17:48:13 -07002173 for (SQLiteDatabase db : getActiveDatabases()) {
2174 db.collectDbStats(dbStatsList);
Vasu Nori24675612010-09-27 14:54:19 -07002175 }
Vasu Noric3849202010-03-09 10:47:25 -08002176 return dbStatsList;
2177 }
2178
Mathew Inwood41b31942018-08-10 16:00:53 +01002179 @UnsupportedAppUsage
Jeff Browne5360fb2011-10-31 17:48:13 -07002180 private void collectDbStats(ArrayList<DbStats> dbStatsList) {
2181 synchronized (mLock) {
2182 if (mConnectionPoolLocked != null) {
2183 mConnectionPoolLocked.collectDbStats(dbStatsList);
2184 }
2185 }
2186 }
2187
Mathew Inwood41b31942018-08-10 16:00:53 +01002188 @UnsupportedAppUsage
Jeff Browne5360fb2011-10-31 17:48:13 -07002189 private static ArrayList<SQLiteDatabase> getActiveDatabases() {
2190 ArrayList<SQLiteDatabase> databases = new ArrayList<SQLiteDatabase>();
2191 synchronized (sActiveDatabases) {
2192 databases.addAll(sActiveDatabases.keySet());
2193 }
2194 return databases;
2195 }
2196
2197 /**
2198 * Dump detailed information about all open databases in the current process.
2199 * Used by bug report.
2200 */
Makoto Onukiee93ad22018-10-18 16:24:13 -07002201 static void dumpAll(Printer printer, boolean verbose, boolean isSystem) {
2202 // Use this ArraySet to collect file paths.
2203 final ArraySet<String> directories = new ArraySet<>();
2204
Jeff Browne5360fb2011-10-31 17:48:13 -07002205 for (SQLiteDatabase db : getActiveDatabases()) {
Makoto Onukiee93ad22018-10-18 16:24:13 -07002206 db.dump(printer, verbose, isSystem, directories);
2207 }
2208
2209 // Dump DB files in the directories.
2210 if (directories.size() > 0) {
2211 final String[] dirs = directories.toArray(new String[directories.size()]);
2212 Arrays.sort(dirs);
2213 for (String dir : dirs) {
2214 dumpDatabaseDirectory(printer, new File(dir), isSystem);
2215 }
Jeff Browne5360fb2011-10-31 17:48:13 -07002216 }
2217 }
2218
Makoto Onukiee93ad22018-10-18 16:24:13 -07002219 private void dump(Printer printer, boolean verbose, boolean isSystem, ArraySet directories) {
Jeff Browne5360fb2011-10-31 17:48:13 -07002220 synchronized (mLock) {
2221 if (mConnectionPoolLocked != null) {
2222 printer.println("");
Makoto Onukiee93ad22018-10-18 16:24:13 -07002223 mConnectionPoolLocked.dump(printer, verbose, directories);
Jeff Browne5360fb2011-10-31 17:48:13 -07002224 }
2225 }
2226 }
2227
Makoto Onukiee93ad22018-10-18 16:24:13 -07002228 private static void dumpDatabaseDirectory(Printer pw, File dir, boolean isSystem) {
2229 pw.println("");
2230 pw.println("Database files in " + dir.getAbsolutePath() + ":");
2231 final File[] files = dir.listFiles();
2232 if (files == null || files.length == 0) {
2233 pw.println(" [none]");
2234 return;
2235 }
2236 Arrays.sort(files, (a, b) -> a.getName().compareTo(b.getName()));
2237
2238 for (File f : files) {
2239 if (isSystem) {
2240 // If called within the system server, the directory contains other files too, so
2241 // filter by file extensions.
2242 // (If it's an app, just print all files because they may not use *.db
2243 // extension.)
2244 final String name = f.getName();
2245 if (!(name.endsWith(".db") || name.endsWith(".db-wal")
2246 || name.endsWith(".db-journal")
2247 || name.endsWith(SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX))) {
2248 continue;
2249 }
2250 }
2251 pw.println(String.format(" %-40s %7db %s", f.getName(), f.length(),
2252 SQLiteDatabase.getFileTimestamps(f.getAbsolutePath())));
2253 }
2254 }
2255
Vasu Noric3849202010-03-09 10:47:25 -08002256 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002257 * Returns list of full pathnames of all attached databases including the main database
2258 * by executing 'pragma database_list' on the database.
2259 *
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002260 * @return ArrayList of pairs of (database name, database file path) or null if the database
2261 * is not open.
Vasu Noric3849202010-03-09 10:47:25 -08002262 */
Vasu Noria017eda2011-01-27 10:52:55 -08002263 public List<Pair<String, String>> getAttachedDbs() {
Vasu Noric3849202010-03-09 10:47:25 -08002264 ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
Jeff Browne5360fb2011-10-31 17:48:13 -07002265 synchronized (mLock) {
2266 if (mConnectionPoolLocked == null) {
2267 return null; // not open
2268 }
2269
2270 if (!mHasAttachedDbsLocked) {
2271 // No attached databases.
2272 // There is a small window where attached databases exist but this flag is not
2273 // set yet. This can occur when this thread is in a race condition with another
2274 // thread that is executing the SQL statement: "attach database <blah> as <foo>"
2275 // If this thread is NOT ok with such a race condition (and thus possibly not
2276 // receivethe entire list of attached databases), then the caller should ensure
2277 // that no thread is executing any SQL statements while a thread is calling this
2278 // method. Typically, this method is called when 'adb bugreport' is done or the
2279 // caller wants to collect stats on the database and all its attached databases.
2280 attachedDbs.add(new Pair<String, String>("main", mConfigurationLocked.path));
2281 return attachedDbs;
2282 }
Jeff Brown03bd3022012-03-06 13:48:56 -08002283
2284 acquireReference();
Vasu Nori24675612010-09-27 14:54:19 -07002285 }
Jeff Browne5360fb2011-10-31 17:48:13 -07002286
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002287 try {
Jeff Brown03bd3022012-03-06 13:48:56 -08002288 // has attached databases. query sqlite to get the list of attached databases.
2289 Cursor c = null;
2290 try {
2291 c = rawQuery("pragma database_list;", null);
2292 while (c.moveToNext()) {
2293 // sqlite returns a row for each database in the returned list of databases.
2294 // in each row,
2295 // 1st column is the database name such as main, or the database
2296 // name specified on the "ATTACH" command
2297 // 2nd column is the database file path.
2298 attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
2299 }
2300 } finally {
2301 if (c != null) {
2302 c.close();
2303 }
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002304 }
Jeff Brown03bd3022012-03-06 13:48:56 -08002305 return attachedDbs;
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002306 } finally {
Jeff Brown03bd3022012-03-06 13:48:56 -08002307 releaseReference();
Vasu Noric3849202010-03-09 10:47:25 -08002308 }
Vasu Noric3849202010-03-09 10:47:25 -08002309 }
2310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002312 * Runs 'pragma integrity_check' on the given database (and all the attached databases)
2313 * and returns true if the given database (and all its attached databases) pass integrity_check,
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002314 * false otherwise.
Vasu Noriccd95442010-05-28 17:04:16 -07002315 *<p>
2316 * If the result is false, then this method logs the errors reported by the integrity_check
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002317 * command execution.
Vasu Noriccd95442010-05-28 17:04:16 -07002318 *<p>
2319 * Note that 'pragma integrity_check' on a database can take a long time.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002320 *
2321 * @return true if the given database (and all its attached databases) pass integrity_check,
Vasu Noriccd95442010-05-28 17:04:16 -07002322 * false otherwise.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002323 */
2324 public boolean isDatabaseIntegrityOk() {
Jeff Brown03bd3022012-03-06 13:48:56 -08002325 acquireReference();
Vasu Noribfe1dc22010-08-25 16:29:02 -07002326 try {
Jeff Brown03bd3022012-03-06 13:48:56 -08002327 List<Pair<String, String>> attachedDbs = null;
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002328 try {
Jeff Brown03bd3022012-03-06 13:48:56 -08002329 attachedDbs = getAttachedDbs();
2330 if (attachedDbs == null) {
2331 throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
2332 "be retrieved. probably because the database is closed");
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002333 }
Jeff Brown03bd3022012-03-06 13:48:56 -08002334 } catch (SQLiteException e) {
2335 // can't get attachedDb list. do integrity check on the main database
2336 attachedDbs = new ArrayList<Pair<String, String>>();
2337 attachedDbs.add(new Pair<String, String>("main", getPath()));
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002338 }
Jeff Brown03bd3022012-03-06 13:48:56 -08002339
2340 for (int i = 0; i < attachedDbs.size(); i++) {
2341 Pair<String, String> p = attachedDbs.get(i);
2342 SQLiteStatement prog = null;
2343 try {
2344 prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);");
2345 String rslt = prog.simpleQueryForString();
2346 if (!rslt.equalsIgnoreCase("ok")) {
2347 // integrity_checker failed on main or attached databases
2348 Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt);
2349 return false;
2350 }
2351 } finally {
2352 if (prog != null) prog.close();
2353 }
2354 }
2355 } finally {
2356 releaseReference();
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002357 }
Vasu Noribfe1dc22010-08-25 16:29:02 -07002358 return true;
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002359 }
2360
Jeff Browne5360fb2011-10-31 17:48:13 -07002361 @Override
2362 public String toString() {
2363 return "SQLiteDatabase: " + getPath();
2364 }
2365
Jeff Browne5360fb2011-10-31 17:48:13 -07002366 private void throwIfNotOpenLocked() {
2367 if (mConnectionPoolLocked == null) {
2368 throw new IllegalStateException("The database '" + mConfigurationLocked.label
2369 + "' is not open.");
2370 }
2371 }
Vasu Nori3ef94e22010-02-05 14:49:04 -08002372
2373 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07002374 * Used to allow returning sub-classes of {@link Cursor} when calling query.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002375 */
Jeff Browne5360fb2011-10-31 17:48:13 -07002376 public interface CursorFactory {
2377 /**
2378 * See {@link SQLiteCursor#SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)}.
2379 */
2380 public Cursor newCursor(SQLiteDatabase db,
2381 SQLiteCursorDriver masterQuery, String editTable,
2382 SQLiteQuery query);
2383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384
2385 /**
Jeff Browne5360fb2011-10-31 17:48:13 -07002386 * A callback interface for a custom sqlite3 function.
2387 * This can be used to create a function that can be called from
2388 * sqlite3 database triggers.
2389 * @hide
Vasu Noric3849202010-03-09 10:47:25 -08002390 */
Jeff Browne5360fb2011-10-31 17:48:13 -07002391 public interface CustomFunction {
2392 public void callback(String[] args);
2393 }
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002394
2395 /**
2396 * Wrapper for configuration parameters that are used for opening {@link SQLiteDatabase}
2397 */
2398 public static final class OpenParams {
2399 private final int mOpenFlags;
2400 private final CursorFactory mCursorFactory;
2401 private final DatabaseErrorHandler mErrorHandler;
2402 private final int mLookasideSlotSize;
2403 private final int mLookasideSlotCount;
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002404 private final long mIdleConnectionTimeout;
2405 private final String mJournalMode;
2406 private final String mSyncMode;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002407
2408 private OpenParams(int openFlags, CursorFactory cursorFactory,
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002409 DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002410 long idleConnectionTimeout, String journalMode, String syncMode) {
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002411 mOpenFlags = openFlags;
2412 mCursorFactory = cursorFactory;
2413 mErrorHandler = errorHandler;
2414 mLookasideSlotSize = lookasideSlotSize;
2415 mLookasideSlotCount = lookasideSlotCount;
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002416 mIdleConnectionTimeout = idleConnectionTimeout;
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002417 mJournalMode = journalMode;
2418 mSyncMode = syncMode;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002419 }
2420
2421 /**
2422 * Returns size in bytes of each lookaside slot or -1 if not set.
2423 *
2424 * @see Builder#setLookasideConfig(int, int)
2425 */
2426 @IntRange(from = -1)
2427 public int getLookasideSlotSize() {
2428 return mLookasideSlotSize;
2429 }
2430
2431 /**
2432 * Returns total number of lookaside memory slots per database connection or -1 if not
2433 * set.
2434 *
2435 * @see Builder#setLookasideConfig(int, int)
2436 */
2437 @IntRange(from = -1)
2438 public int getLookasideSlotCount() {
2439 return mLookasideSlotCount;
2440 }
2441
2442 /**
Fyodor Kupolov76436c02017-08-03 17:56:44 -07002443 * Returns flags to control database access mode. Default value is 0.
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002444 *
2445 * @see Builder#setOpenFlags(int)
2446 */
2447 @DatabaseOpenFlags
2448 public int getOpenFlags() {
2449 return mOpenFlags;
2450 }
2451
2452 /**
2453 * Returns an optional factory class that is called to instantiate a cursor when query
2454 * is called
2455 *
2456 * @see Builder#setCursorFactory(CursorFactory)
2457 */
2458 @Nullable
2459 public CursorFactory getCursorFactory() {
2460 return mCursorFactory;
2461 }
2462
2463 /**
2464 * Returns handler for database corruption errors
2465 *
2466 * @see Builder#setErrorHandler(DatabaseErrorHandler)
2467 */
2468 @Nullable
2469 public DatabaseErrorHandler getErrorHandler() {
2470 return mErrorHandler;
2471 }
2472
2473 /**
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002474 * Returns maximum number of milliseconds that SQLite connection is allowed to be idle
2475 * before it is closed and removed from the pool.
2476 * <p>If the value isn't set, the timeout defaults to the system wide timeout
2477 *
2478 * @return timeout in milliseconds or -1 if the value wasn't set.
2479 */
2480 public long getIdleConnectionTimeout() {
2481 return mIdleConnectionTimeout;
2482 }
2483
2484 /**
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002485 * Returns <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>.
2486 * This journal mode will only be used if {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING}
2487 * flag is not set, otherwise a platform will use "WAL" journal mode.
2488 * @see Builder#setJournalMode(String)
2489 */
2490 @Nullable
2491 public String getJournalMode() {
2492 return mJournalMode;
2493 }
2494
2495 /**
2496 * Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>.
Fyodor Kupolov8ba20892018-06-01 12:11:42 -07002497 * If not set, a system wide default will be used.
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002498 * @see Builder#setSynchronousMode(String)
2499 */
2500 @Nullable
2501 public String getSynchronousMode() {
2502 return mSyncMode;
2503 }
2504
2505 /**
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002506 * Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
2507 * {@code this} parameters.
2508 * @hide
2509 */
2510 @NonNull
2511 public Builder toBuilder() {
2512 return new Builder(this);
2513 }
2514
2515 /**
2516 * Builder for {@link OpenParams}.
2517 */
2518 public static final class Builder {
2519 private int mLookasideSlotSize = -1;
2520 private int mLookasideSlotCount = -1;
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002521 private long mIdleConnectionTimeout = -1;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002522 private int mOpenFlags;
2523 private CursorFactory mCursorFactory;
2524 private DatabaseErrorHandler mErrorHandler;
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002525 private String mJournalMode;
2526 private String mSyncMode;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002527
2528 public Builder() {
2529 }
2530
2531 public Builder(OpenParams params) {
2532 mLookasideSlotSize = params.mLookasideSlotSize;
2533 mLookasideSlotCount = params.mLookasideSlotCount;
2534 mOpenFlags = params.mOpenFlags;
2535 mCursorFactory = params.mCursorFactory;
2536 mErrorHandler = params.mErrorHandler;
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002537 mJournalMode = params.mJournalMode;
2538 mSyncMode = params.mSyncMode;
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002539 }
2540
2541 /**
2542 * Configures
2543 * <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
2544 *
2545 * <p>SQLite default settings will be used, if this method isn't called.
2546 * Use {@code setLookasideConfig(0,0)} to disable lookaside
2547 *
Fyodor Kupolov05a0f0f2017-06-30 19:00:00 -07002548 * <p><strong>Note:</strong> Provided slotSize/slotCount configuration is just a
2549 * recommendation. The system may choose different values depending on a device, e.g.
2550 * lookaside allocations can be disabled on low-RAM devices
2551 *
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002552 * @param slotSize The size in bytes of each lookaside slot.
2553 * @param slotCount The total number of lookaside memory slots per database connection.
2554 */
2555 public Builder setLookasideConfig(@IntRange(from = 0) final int slotSize,
2556 @IntRange(from = 0) final int slotCount) {
2557 Preconditions.checkArgument(slotSize >= 0,
2558 "lookasideSlotCount cannot be negative");
2559 Preconditions.checkArgument(slotCount >= 0,
2560 "lookasideSlotSize cannot be negative");
2561 Preconditions.checkArgument(
2562 (slotSize > 0 && slotCount > 0) || (slotCount == 0 && slotSize == 0),
2563 "Invalid configuration: " + slotSize + ", " + slotCount);
2564
2565 mLookasideSlotSize = slotSize;
2566 mLookasideSlotCount = slotCount;
2567 return this;
2568 }
2569
2570 /**
2571 * Returns true if {@link #ENABLE_WRITE_AHEAD_LOGGING} flag is set
2572 * @hide
2573 */
2574 public boolean isWriteAheadLoggingEnabled() {
2575 return (mOpenFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
2576 }
2577
2578 /**
2579 * Sets flags to control database access mode
2580 * @param openFlags The new flags to set
2581 * @see #OPEN_READWRITE
2582 * @see #OPEN_READONLY
2583 * @see #CREATE_IF_NECESSARY
2584 * @see #NO_LOCALIZED_COLLATORS
2585 * @see #ENABLE_WRITE_AHEAD_LOGGING
2586 * @return same builder instance for chaining multiple calls into a single statement
2587 */
2588 @NonNull
2589 public Builder setOpenFlags(@DatabaseOpenFlags int openFlags) {
2590 mOpenFlags = openFlags;
2591 return this;
2592 }
2593
2594 /**
2595 * Adds flags to control database access mode
2596 *
2597 * @param openFlags The new flags to add
2598 * @return same builder instance for chaining multiple calls into a single statement
2599 */
2600 @NonNull
2601 public Builder addOpenFlags(@DatabaseOpenFlags int openFlags) {
2602 mOpenFlags |= openFlags;
2603 return this;
2604 }
2605
2606 /**
2607 * Removes database access mode flags
2608 *
2609 * @param openFlags Flags to remove
2610 * @return same builder instance for chaining multiple calls into a single statement
2611 */
2612 @NonNull
2613 public Builder removeOpenFlags(@DatabaseOpenFlags int openFlags) {
2614 mOpenFlags &= ~openFlags;
2615 return this;
2616 }
2617
2618 /**
2619 * Sets {@link #ENABLE_WRITE_AHEAD_LOGGING} flag if {@code enabled} is {@code true},
2620 * unsets otherwise
2621 * @hide
2622 */
2623 public void setWriteAheadLoggingEnabled(boolean enabled) {
2624 if (enabled) {
2625 addOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
2626 } else {
2627 removeOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
2628 }
2629 }
2630
2631 /**
2632 * Set an optional factory class that is called to instantiate a cursor when query
2633 * is called.
2634 *
2635 * @param cursorFactory instance
2636 * @return same builder instance for chaining multiple calls into a single statement
2637 */
2638 @NonNull
2639 public Builder setCursorFactory(@Nullable CursorFactory cursorFactory) {
2640 mCursorFactory = cursorFactory;
2641 return this;
2642 }
2643
2644
2645 /**
2646 * Sets {@link DatabaseErrorHandler} object to handle db corruption errors
2647 */
2648 @NonNull
2649 public Builder setErrorHandler(@Nullable DatabaseErrorHandler errorHandler) {
2650 mErrorHandler = errorHandler;
2651 return this;
2652 }
2653
2654 /**
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002655 * Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
2656 * before it is closed and removed from the pool.
2657 *
Makoto Onuki1a904792019-02-28 12:04:52 -08002658 * <p><b>DO NOT USE</b> this method.
2659 * This feature has negative side effects that are very hard to foresee.
2660 * <p>A connection timeout allows the system to internally close a connection to
2661 * a SQLite database after a given timeout, which is good for reducing app's memory
2662 * consumption.
2663 * <b>However</b> the side effect is it <b>will reset all of SQLite's per-connection
2664 * states</b>, which are typically modified with a {@code PRAGMA} statement, and
2665 * these states <b>will not be restored</b> when a connection is re-established
2666 * internally, and the system does not provide a callback for an app to reconfigure a
2667 * connection.
2668 * This feature may only be used if an app relies on none of such per-connection states.
Makoto Onukib15186c2019-01-28 14:43:41 -08002669 *
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002670 * @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE}
2671 * to allow unlimited idle connections.
Makoto Onukib15186c2019-01-28 14:43:41 -08002672 *
2673 * @see SQLiteOpenHelper#setIdleConnectionTimeout(long)
2674 *
Makoto Onuki1a904792019-02-28 12:04:52 -08002675 * @deprecated DO NOT USE this method. See the javadoc for the details.
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002676 */
2677 @NonNull
Makoto Onukib15186c2019-01-28 14:43:41 -08002678 @Deprecated
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002679 public Builder setIdleConnectionTimeout(
2680 @IntRange(from = 0) long idleConnectionTimeoutMs) {
2681 Preconditions.checkArgument(idleConnectionTimeoutMs >= 0,
2682 "idle connection timeout cannot be negative");
2683 mIdleConnectionTimeout = idleConnectionTimeoutMs;
2684 return this;
2685 }
2686
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002687
2688 /**
2689 * Sets <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>
2690 * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
2691 */
2692 @NonNull
2693 public Builder setJournalMode(@NonNull String journalMode) {
2694 Preconditions.checkNotNull(journalMode);
2695 mJournalMode = journalMode;
2696 return this;
2697 }
2698
Makoto Onukiee93ad22018-10-18 16:24:13 -07002699 /**w
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002700 * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
Fyodor Kupolov8ba20892018-06-01 12:11:42 -07002701 * .
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002702 * @return
2703 */
2704 @NonNull
2705 public Builder setSynchronousMode(@NonNull String syncMode) {
2706 Preconditions.checkNotNull(syncMode);
2707 mSyncMode = syncMode;
2708 return this;
2709 }
2710
Fyodor Kupolovcf97b6b2017-07-25 14:17:33 -07002711 /**
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002712 * Creates an instance of {@link OpenParams} with the options that were previously set
2713 * on this builder
2714 */
2715 @NonNull
2716 public OpenParams build() {
2717 return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002718 mLookasideSlotCount, mIdleConnectionTimeout, mJournalMode, mSyncMode);
Fyodor Kupolovd3b0c7e2017-06-20 11:51:55 -07002719 }
2720 }
2721 }
2722
2723 /** @hide */
2724 @IntDef(flag = true, prefix = {"OPEN_", "CREATE_", "NO_", "ENABLE_"}, value = {
2725 OPEN_READWRITE,
2726 OPEN_READONLY,
2727 CREATE_IF_NECESSARY,
2728 NO_LOCALIZED_COLLATORS,
2729 ENABLE_WRITE_AHEAD_LOGGING
2730 })
2731 @Retention(RetentionPolicy.SOURCE)
2732 public @interface DatabaseOpenFlags {}
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002733
Makoto Onukiee93ad22018-10-18 16:24:13 -07002734 /** @hide */
2735 public static void wipeDetected(String filename, String reason) {
2736 wtfAsSystemServer(TAG, "DB wipe detected:"
2737 + " package=" + ActivityThread.currentPackageName()
2738 + " reason=" + reason
2739 + " file=" + filename
2740 + " " + getFileTimestamps(filename)
2741 + " checkfile " + getFileTimestamps(filename + SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX),
2742 new Throwable("STACKTRACE"));
2743 }
2744
2745 /** @hide */
2746 public static String getFileTimestamps(String path) {
2747 try {
2748 BasicFileAttributes attr = Files.readAttributes(
2749 FileSystems.getDefault().getPath(path), BasicFileAttributes.class);
2750 return "ctime=" + attr.creationTime()
2751 + " mtime=" + attr.lastModifiedTime()
2752 + " atime=" + attr.lastAccessTime();
2753 } catch (IOException e) {
2754 return "[unable to obtain timestamp]";
2755 }
2756 }
2757
2758 /** @hide */
2759 static void wtfAsSystemServer(String tag, String message, Throwable stacktrace) {
2760 Log.e(tag, message, stacktrace);
2761 ContentResolver.onDbCorruption(tag, message, stacktrace);
2762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763}
Fyodor Kupolov13a4b372017-11-07 18:45:35 -08002764