diff options
| -rw-r--r-- | api/current.txt | 5 | ||||
| -rw-r--r-- | api/system-current.txt | 5 | ||||
| -rw-r--r-- | api/test-current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteConnection.java | 23 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteDatabase.java | 72 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java | 14 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteOpenHelper.java | 52 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java | 26 |
8 files changed, 178 insertions, 24 deletions
diff --git a/api/current.txt b/api/current.txt index a7afa2532867..b9dfd94ff598 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12121,9 +12121,11 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); method public long getIdleConnectionTimeout(); + method public java.lang.String getJournalMode(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); + method public java.lang.String getSynchronousMode(); } public static final class SQLiteDatabase.OpenParams.Builder { @@ -12135,8 +12137,10 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String); } public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException { @@ -12183,6 +12187,7 @@ package android.database.sqlite { public abstract class SQLiteOpenHelper { ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int); ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler); + ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams); method public synchronized void close(); method public java.lang.String getDatabaseName(); method public android.database.sqlite.SQLiteDatabase getReadableDatabase(); diff --git a/api/system-current.txt b/api/system-current.txt index e213960b85dd..b3988633ac53 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12868,9 +12868,11 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); method public long getIdleConnectionTimeout(); + method public java.lang.String getJournalMode(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); + method public java.lang.String getSynchronousMode(); } public static final class SQLiteDatabase.OpenParams.Builder { @@ -12882,8 +12884,10 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String); } public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException { @@ -12930,6 +12934,7 @@ package android.database.sqlite { public abstract class SQLiteOpenHelper { ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int); ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler); + ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams); method public synchronized void close(); method public java.lang.String getDatabaseName(); method public android.database.sqlite.SQLiteDatabase getReadableDatabase(); diff --git a/api/test-current.txt b/api/test-current.txt index ec6319fd0992..28614ad262ac 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12211,9 +12211,11 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); method public long getIdleConnectionTimeout(); + method public java.lang.String getJournalMode(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); + method public java.lang.String getSynchronousMode(); } public static final class SQLiteDatabase.OpenParams.Builder { @@ -12225,8 +12227,10 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String); } public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException { @@ -12319,6 +12323,7 @@ package android.database.sqlite { public abstract class SQLiteOpenHelper { ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int); ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler); + ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams); method public synchronized void close(); method public java.lang.String getDatabaseName(); method public android.database.sqlite.SQLiteDatabase getReadableDatabase(); diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 361b81b77f1d..23c0720488d6 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -289,14 +289,19 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen private void setWalModeFromConfiguration() { if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { - boolean walEnabled = + final boolean walEnabled = (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; - if (walEnabled || mConfiguration.useCompatibilityWal) { + // Use compatibility WAL unless an app explicitly set journal/synchronous mode + final boolean useCompatibilityWal = mConfiguration.journalMode == null + && mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal; + if (walEnabled || useCompatibilityWal) { setJournalMode("WAL"); setSyncMode(SQLiteGlobal.getWALSyncMode()); } else { - setJournalMode(SQLiteGlobal.getDefaultJournalMode()); - setSyncMode(SQLiteGlobal.getDefaultSyncMode()); + setJournalMode(mConfiguration.journalMode == null + ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); + setSyncMode(mConfiguration.syncMode == null + ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode); } } } @@ -310,12 +315,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } private static String canonicalizeSyncMode(String value) { - if (value.equals("0")) { - return "OFF"; - } else if (value.equals("1")) { - return "NORMAL"; - } else if (value.equals("2")) { - return "FULL"; + switch (value) { + case "0": return "OFF"; + case "1": return "NORMAL"; + case "2": return "FULL"; } return value; } diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 83b8dc76bfc3..863fb1986e06 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -262,7 +262,8 @@ public final class SQLiteDatabase extends SQLiteClosable { private SQLiteDatabase(final String path, final int openFlags, CursorFactory cursorFactory, DatabaseErrorHandler errorHandler, - int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs) { + int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs, + String journalMode, String syncMode) { mCursorFactory = cursorFactory; mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler(); mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags); @@ -285,6 +286,8 @@ public final class SQLiteDatabase extends SQLiteClosable { } } mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs; + mConfigurationLocked.journalMode = journalMode; + mConfigurationLocked.syncMode = syncMode; mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported(); } @@ -721,7 +724,7 @@ public final class SQLiteDatabase extends SQLiteClosable { SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags, openParams.mCursorFactory, openParams.mErrorHandler, openParams.mLookasideSlotSize, openParams.mLookasideSlotCount, - openParams.mIdleConnectionTimeout); + openParams.mIdleConnectionTimeout, openParams.mJournalMode, openParams.mSyncMode); db.open(); return db; } @@ -747,7 +750,8 @@ public final class SQLiteDatabase extends SQLiteClosable { */ public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) { - SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1); + SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1, null, + null); db.open(); return db; } @@ -2302,17 +2306,21 @@ public final class SQLiteDatabase extends SQLiteClosable { private final DatabaseErrorHandler mErrorHandler; private final int mLookasideSlotSize; private final int mLookasideSlotCount; - private long mIdleConnectionTimeout; + private final long mIdleConnectionTimeout; + private final String mJournalMode; + private final String mSyncMode; private OpenParams(int openFlags, CursorFactory cursorFactory, DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount, - long idleConnectionTimeout) { + long idleConnectionTimeout, String journalMode, String syncMode) { mOpenFlags = openFlags; mCursorFactory = cursorFactory; mErrorHandler = errorHandler; mLookasideSlotSize = lookasideSlotSize; mLookasideSlotCount = lookasideSlotCount; mIdleConnectionTimeout = idleConnectionTimeout; + mJournalMode = journalMode; + mSyncMode = syncMode; } /** @@ -2379,6 +2387,28 @@ public final class SQLiteDatabase extends SQLiteClosable { } /** + * Returns <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>. + * This journal mode will only be used if {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} + * flag is not set, otherwise a platform will use "WAL" journal mode. + * @see Builder#setJournalMode(String) + */ + @Nullable + public String getJournalMode() { + return mJournalMode; + } + + /** + * Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>. + * This value will only be used when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag + * is not set, otherwise a system wide default will be used. + * @see Builder#setSynchronousMode(String) + */ + @Nullable + public String getSynchronousMode() { + return mSyncMode; + } + + /** * Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with * {@code this} parameters. * @hide @@ -2398,6 +2428,8 @@ public final class SQLiteDatabase extends SQLiteClosable { private int mOpenFlags; private CursorFactory mCursorFactory; private DatabaseErrorHandler mErrorHandler; + private String mJournalMode; + private String mSyncMode; public Builder() { } @@ -2408,6 +2440,8 @@ public final class SQLiteDatabase extends SQLiteClosable { mOpenFlags = params.mOpenFlags; mCursorFactory = params.mCursorFactory; mErrorHandler = params.mErrorHandler; + mJournalMode = params.mJournalMode; + mSyncMode = params.mSyncMode; } /** @@ -2539,6 +2573,30 @@ public final class SQLiteDatabase extends SQLiteClosable { return this; } + + /** + * Sets <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a> + * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set. + */ + @NonNull + public Builder setJournalMode(@NonNull String journalMode) { + Preconditions.checkNotNull(journalMode); + mJournalMode = journalMode; + return this; + } + + /** + * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a> + * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set. + * @return + */ + @NonNull + public Builder setSynchronousMode(@NonNull String syncMode) { + Preconditions.checkNotNull(syncMode); + mSyncMode = syncMode; + return this; + } + /** * Creates an instance of {@link OpenParams} with the options that were previously set * on this builder @@ -2546,7 +2604,7 @@ public final class SQLiteDatabase extends SQLiteClosable { @NonNull public OpenParams build() { return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize, - mLookasideSlotCount, mIdleConnectionTimeout); + mLookasideSlotCount, mIdleConnectionTimeout, mJournalMode, mSyncMode); } } } @@ -2561,4 +2619,6 @@ public final class SQLiteDatabase extends SQLiteClosable { }) @Retention(RetentionPolicy.SOURCE) public @interface DatabaseOpenFlags {} + } + diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index 905da7247308..a14df1ebcbc6 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -120,6 +120,18 @@ public final class SQLiteDatabaseConfiguration { public boolean useCompatibilityWal; /** + * Journal mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set. + * <p>Default is returned by {@link SQLiteGlobal#getDefaultJournalMode()} + */ + public String journalMode; + + /** + * Synchronous mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set. + * <p>Default is returned by {@link SQLiteGlobal#getDefaultSyncMode()} + */ + public String syncMode; + + /** * Creates a database configuration with the required parameters for opening a * database and default values for all other parameters. * @@ -180,6 +192,8 @@ public final class SQLiteDatabaseConfiguration { lookasideSlotCount = other.lookasideSlotCount; idleConnectionTimeoutMs = other.idleConnectionTimeoutMs; useCompatibilityWal = other.useCompatibilityWal; + journalMode = other.journalMode; + syncMode = other.syncMode; } /** diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index cc9e0f4ded84..d4699a8d71cd 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -17,6 +17,8 @@ package android.database.sqlite; import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.database.DatabaseErrorHandler; import android.database.SQLException; @@ -24,6 +26,8 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.os.FileUtils; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.io.File; /** @@ -69,7 +73,8 @@ public abstract class SQLiteOpenHelper { * {@link #onUpgrade} will be used to upgrade the database; if the database is * newer, {@link #onDowngrade} will be used to downgrade the database */ - public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) { + public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, + @Nullable CursorFactory factory, int version) { this(context, name, factory, version, null); } @@ -90,12 +95,33 @@ public abstract class SQLiteOpenHelper { * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database * corruption, or null to use the default error handler. */ - public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, - DatabaseErrorHandler errorHandler) { + public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, + @Nullable CursorFactory factory, int version, + @Nullable DatabaseErrorHandler errorHandler) { this(context, name, factory, version, 0, errorHandler); } /** + * Create a helper object to create, open, and/or manage a database. + * This method always returns very quickly. The database is not actually + * created or opened until one of {@link #getWritableDatabase} or + * {@link #getReadableDatabase} is called. + * + * @param context to use to open or create the database + * @param name of the database file, or null for an in-memory database + * @param version number of the database (starting at 1); if the database is older, + * {@link #onUpgrade} will be used to upgrade the database; if the database is + * newer, {@link #onDowngrade} will be used to downgrade the database + * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}. + * Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be + * set when the helper opens the database + */ + public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version, + @NonNull SQLiteDatabase.OpenParams openParams) { + this(context, name, version, 0, openParams.toBuilder()); + } + + /** * Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)} * but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old * versions of this database that are no longer supported. If a database with older version that @@ -118,17 +144,27 @@ public abstract class SQLiteOpenHelper { * @see #onUpgrade(SQLiteDatabase, int, int) * @hide */ - public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, - int minimumSupportedVersion, DatabaseErrorHandler errorHandler) { + public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, + @Nullable CursorFactory factory, int version, + int minimumSupportedVersion, @Nullable DatabaseErrorHandler errorHandler) { + this(context, name, version, minimumSupportedVersion, + new SQLiteDatabase.OpenParams.Builder()); + mOpenParamsBuilder.setCursorFactory(factory); + mOpenParamsBuilder.setErrorHandler(errorHandler); + } + + private SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version, + int minimumSupportedVersion, + @NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) { + Preconditions.checkNotNull(context); + Preconditions.checkNotNull(openParamsBuilder); if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version); mContext = context; mName = name; mNewVersion = version; mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion); - mOpenParamsBuilder = new SQLiteDatabase.OpenParams.Builder(); - mOpenParamsBuilder.setCursorFactory(factory); - mOpenParamsBuilder.setErrorHandler(errorHandler); + mOpenParamsBuilder = openParamsBuilder; mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY); } diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java index 75eeb93f5b9a..9ed3f11b548f 100644 --- a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java +++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java @@ -16,6 +16,7 @@ package android.database; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -61,6 +62,10 @@ public class SQLiteOpenHelperTest { super(context, name, null, 1); } + TestHelper(Context context, String name, int version, SQLiteDatabase.OpenParams params) { + super(context, name, version, params); + } + @Override public void onCreate(SQLiteDatabase db) { } @@ -168,4 +173,25 @@ public class SQLiteOpenHelperTest { } assertTrue("No dbstat found for " + dbName, dbStatFound); } + + @Test + public void testOpenParamsConstructor() { + SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder() + .setJournalMode("DELETE") + .setSynchronousMode("OFF") + .build(); + + TestHelper helper = new TestHelper(mContext, "openhelper_test_constructor", 1, params); + mHelpersToClose.add(helper); + + String journalMode = DatabaseUtils + .stringForQuery(helper.getReadableDatabase(), "PRAGMA journal_mode", null); + + assertEquals("DELETE", journalMode.toUpperCase()); + String syncMode = DatabaseUtils + .stringForQuery(helper.getReadableDatabase(), "PRAGMA synchronous", null); + + assertEquals("0", syncMode); + } + } |