Merge "Support for lookaside configuration params"
This commit is contained in:
committed by
Android (Google) Code Review
commit
db0da015de
@@ -11872,6 +11872,7 @@ package android.database.sqlite {
|
||||
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
|
||||
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
|
||||
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
|
||||
method public static boolean deleteDatabase(java.io.File);
|
||||
method public void disableWriteAheadLogging();
|
||||
@@ -11901,6 +11902,7 @@ package android.database.sqlite {
|
||||
method public boolean needUpgrade(int);
|
||||
method protected void onAllReferencesReleased();
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
@@ -11951,6 +11953,26 @@ package android.database.sqlite {
|
||||
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams.Builder {
|
||||
ctor public SQLiteDatabase.OpenParams.Builder();
|
||||
ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams build();
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
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 setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
|
||||
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
|
||||
ctor public SQLiteDatabaseCorruptException();
|
||||
ctor public SQLiteDatabaseCorruptException(java.lang.String);
|
||||
@@ -12004,6 +12026,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
|
||||
@@ -12659,6 +12659,7 @@ package android.database.sqlite {
|
||||
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
|
||||
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
|
||||
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
|
||||
method public static boolean deleteDatabase(java.io.File);
|
||||
method public void disableWriteAheadLogging();
|
||||
@@ -12688,6 +12689,7 @@ package android.database.sqlite {
|
||||
method public boolean needUpgrade(int);
|
||||
method protected void onAllReferencesReleased();
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
@@ -12738,6 +12740,26 @@ package android.database.sqlite {
|
||||
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams.Builder {
|
||||
ctor public SQLiteDatabase.OpenParams.Builder();
|
||||
ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams build();
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
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 setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
|
||||
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
|
||||
ctor public SQLiteDatabaseCorruptException();
|
||||
ctor public SQLiteDatabaseCorruptException(java.lang.String);
|
||||
@@ -12791,6 +12813,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
|
||||
@@ -11915,6 +11915,7 @@ package android.database.sqlite {
|
||||
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
|
||||
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
|
||||
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
|
||||
method public static boolean deleteDatabase(java.io.File);
|
||||
method public void disableWriteAheadLogging();
|
||||
@@ -11944,6 +11945,7 @@ package android.database.sqlite {
|
||||
method public boolean needUpgrade(int);
|
||||
method protected void onAllReferencesReleased();
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
@@ -11994,6 +11996,26 @@ package android.database.sqlite {
|
||||
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
}
|
||||
|
||||
public static final class SQLiteDatabase.OpenParams.Builder {
|
||||
ctor public SQLiteDatabase.OpenParams.Builder();
|
||||
ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams build();
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
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 setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
|
||||
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
|
||||
ctor public SQLiteDatabaseCorruptException();
|
||||
ctor public SQLiteDatabaseCorruptException(java.lang.String);
|
||||
@@ -12047,6 +12069,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package android.database.sqlite;
|
||||
|
||||
import dalvik.system.BlockGuard;
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWindow;
|
||||
import android.database.DatabaseUtils;
|
||||
@@ -32,11 +29,14 @@ import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Printer;
|
||||
|
||||
import dalvik.system.BlockGuard;
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a SQLite database connection.
|
||||
@@ -118,7 +118,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
private int mCancellationSignalAttachCount;
|
||||
|
||||
private static native long nativeOpen(String path, int openFlags, String label,
|
||||
boolean enableTrace, boolean enableProfile);
|
||||
boolean enableTrace, boolean enableProfile, int lookasideSlotSize,
|
||||
int lookasideSlotCount);
|
||||
private static native void nativeClose(long connectionPtr);
|
||||
private static native void nativeRegisterCustomFunction(long connectionPtr,
|
||||
SQLiteCustomFunction function);
|
||||
@@ -208,8 +209,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
private void open() {
|
||||
mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
|
||||
mConfiguration.label,
|
||||
SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
|
||||
|
||||
SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME,
|
||||
mConfiguration.lookasideSlotSize, mConfiguration.lookasideSlotCount);
|
||||
setPageSize();
|
||||
setForeignKeyModeFromConfiguration();
|
||||
setWalModeFromConfiguration();
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.database.sqlite;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ContentValues;
|
||||
@@ -34,10 +36,14 @@ import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Printer;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -253,11 +259,14 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
*/
|
||||
public static final int MAX_SQL_CACHE_SIZE = 100;
|
||||
|
||||
private SQLiteDatabase(String path, int openFlags, CursorFactory cursorFactory,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
private SQLiteDatabase(final String path, final int openFlags,
|
||||
CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
|
||||
int lookasideSlotSize, int lookasideSlotCount) {
|
||||
mCursorFactory = cursorFactory;
|
||||
mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
|
||||
mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
|
||||
mConfigurationLocked.lookasideSlotSize = lookasideSlotSize;
|
||||
mConfigurationLocked.lookasideSlotCount = lookasideSlotCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -667,10 +676,29 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @return the newly opened database
|
||||
* @throws SQLiteException if the database cannot be opened
|
||||
*/
|
||||
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
|
||||
public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
|
||||
@DatabaseOpenFlags int flags) {
|
||||
return openDatabase(path, factory, flags, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the database according to the specified {@link OpenParams parameters}
|
||||
*
|
||||
* @param path to database file to open and/or create
|
||||
* @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}
|
||||
* @return the newly opened database
|
||||
* @throws SQLiteException if the database cannot be opened
|
||||
*/
|
||||
public static SQLiteDatabase openDatabase(@NonNull String path,
|
||||
@NonNull OpenParams openParams) {
|
||||
Preconditions.checkArgument(openParams != null, "OpenParams cannot be null");
|
||||
SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
|
||||
openParams.mCursorFactory, openParams.mErrorHandler,
|
||||
openParams.mLookasideSlotSize, openParams.mLookasideSlotCount);
|
||||
db.open();
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the database according to the flags {@link #OPEN_READWRITE}
|
||||
* {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
|
||||
@@ -690,9 +718,9 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @return the newly opened database
|
||||
* @throws SQLiteException if the database cannot be opened
|
||||
*/
|
||||
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
|
||||
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);
|
||||
db.open();
|
||||
return db;
|
||||
}
|
||||
@@ -700,22 +728,24 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
/**
|
||||
* Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
|
||||
*/
|
||||
public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
|
||||
public static SQLiteDatabase openOrCreateDatabase(@NonNull File file,
|
||||
@Nullable CursorFactory factory) {
|
||||
return openOrCreateDatabase(file.getPath(), factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
|
||||
*/
|
||||
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
|
||||
public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
|
||||
@Nullable CursorFactory factory) {
|
||||
return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
|
||||
*/
|
||||
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
|
||||
@Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) {
|
||||
return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
|
||||
}
|
||||
|
||||
@@ -726,7 +756,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @param file The database file path.
|
||||
* @return True if the database was successfully deleted.
|
||||
*/
|
||||
public static boolean deleteDatabase(File file) {
|
||||
public static boolean deleteDatabase(@NonNull File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("file must not be null");
|
||||
}
|
||||
@@ -825,12 +855,28 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* cursor when query is called
|
||||
* @return a SQLiteDatabase object, or null if the database can't be created
|
||||
*/
|
||||
public static SQLiteDatabase create(CursorFactory factory) {
|
||||
@NonNull
|
||||
public static SQLiteDatabase create(@Nullable CursorFactory factory) {
|
||||
// This is a magic string with special meaning for SQLite.
|
||||
return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
|
||||
factory, CREATE_IF_NECESSARY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a memory backed SQLite database. Its contents will be destroyed
|
||||
* when the database is closed.
|
||||
*
|
||||
* <p>Sets the locale of the database to the the system's current locale.
|
||||
* Call {@link #setLocale} if you would like something else.</p>
|
||||
* @param openParams configuration parameters that are used for opening SQLiteDatabase
|
||||
* @return a SQLiteDatabase object, or null if the database can't be created
|
||||
*/
|
||||
@NonNull
|
||||
public static SQLiteDatabase createInMemory(@NonNull OpenParams openParams) {
|
||||
return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
|
||||
openParams.toBuilder().addOpenFlags(CREATE_IF_NECESSARY).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a CustomFunction callback as a function that can be called from
|
||||
* SQLite database triggers.
|
||||
@@ -2210,4 +2256,238 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
public interface CustomFunction {
|
||||
public void callback(String[] args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for configuration parameters that are used for opening {@link SQLiteDatabase}
|
||||
*/
|
||||
public static final class OpenParams {
|
||||
private final int mOpenFlags;
|
||||
private final CursorFactory mCursorFactory;
|
||||
private final DatabaseErrorHandler mErrorHandler;
|
||||
private final int mLookasideSlotSize;
|
||||
private final int mLookasideSlotCount;
|
||||
|
||||
private OpenParams(int openFlags, CursorFactory cursorFactory,
|
||||
DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount) {
|
||||
mOpenFlags = openFlags;
|
||||
mCursorFactory = cursorFactory;
|
||||
mErrorHandler = errorHandler;
|
||||
mLookasideSlotSize = lookasideSlotSize;
|
||||
mLookasideSlotCount = lookasideSlotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns size in bytes of each lookaside slot or -1 if not set.
|
||||
*
|
||||
* @see Builder#setLookasideConfig(int, int)
|
||||
*/
|
||||
@IntRange(from = -1)
|
||||
public int getLookasideSlotSize() {
|
||||
return mLookasideSlotSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total number of lookaside memory slots per database connection or -1 if not
|
||||
* set.
|
||||
*
|
||||
* @see Builder#setLookasideConfig(int, int)
|
||||
*/
|
||||
@IntRange(from = -1)
|
||||
public int getLookasideSlotCount() {
|
||||
return mLookasideSlotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns flags to control database access mode
|
||||
*
|
||||
* @see Builder#setOpenFlags(int)
|
||||
*/
|
||||
@DatabaseOpenFlags
|
||||
public int getOpenFlags() {
|
||||
return mOpenFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an optional factory class that is called to instantiate a cursor when query
|
||||
* is called
|
||||
*
|
||||
* @see Builder#setCursorFactory(CursorFactory)
|
||||
*/
|
||||
@Nullable
|
||||
public CursorFactory getCursorFactory() {
|
||||
return mCursorFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns handler for database corruption errors
|
||||
*
|
||||
* @see Builder#setErrorHandler(DatabaseErrorHandler)
|
||||
*/
|
||||
@Nullable
|
||||
public DatabaseErrorHandler getErrorHandler() {
|
||||
return mErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
|
||||
* {@code this} parameters.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Builder toBuilder() {
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link OpenParams}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private int mLookasideSlotSize = -1;
|
||||
private int mLookasideSlotCount = -1;
|
||||
private int mOpenFlags;
|
||||
private CursorFactory mCursorFactory;
|
||||
private DatabaseErrorHandler mErrorHandler;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(OpenParams params) {
|
||||
mLookasideSlotSize = params.mLookasideSlotSize;
|
||||
mLookasideSlotCount = params.mLookasideSlotCount;
|
||||
mOpenFlags = params.mOpenFlags;
|
||||
mCursorFactory = params.mCursorFactory;
|
||||
mErrorHandler = params.mErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures
|
||||
* <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
|
||||
*
|
||||
* <p>SQLite default settings will be used, if this method isn't called.
|
||||
* Use {@code setLookasideConfig(0,0)} to disable lookaside
|
||||
*
|
||||
* @param slotSize The size in bytes of each lookaside slot.
|
||||
* @param slotCount The total number of lookaside memory slots per database connection.
|
||||
*/
|
||||
public Builder setLookasideConfig(@IntRange(from = 0) final int slotSize,
|
||||
@IntRange(from = 0) final int slotCount) {
|
||||
Preconditions.checkArgument(slotSize >= 0,
|
||||
"lookasideSlotCount cannot be negative");
|
||||
Preconditions.checkArgument(slotCount >= 0,
|
||||
"lookasideSlotSize cannot be negative");
|
||||
Preconditions.checkArgument(
|
||||
(slotSize > 0 && slotCount > 0) || (slotCount == 0 && slotSize == 0),
|
||||
"Invalid configuration: " + slotSize + ", " + slotCount);
|
||||
|
||||
mLookasideSlotSize = slotSize;
|
||||
mLookasideSlotCount = slotCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link #ENABLE_WRITE_AHEAD_LOGGING} flag is set
|
||||
* @hide
|
||||
*/
|
||||
public boolean isWriteAheadLoggingEnabled() {
|
||||
return (mOpenFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags to control database access mode
|
||||
* @param openFlags The new flags to set
|
||||
* @see #OPEN_READWRITE
|
||||
* @see #OPEN_READONLY
|
||||
* @see #CREATE_IF_NECESSARY
|
||||
* @see #NO_LOCALIZED_COLLATORS
|
||||
* @see #ENABLE_WRITE_AHEAD_LOGGING
|
||||
* @return same builder instance for chaining multiple calls into a single statement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setOpenFlags(@DatabaseOpenFlags int openFlags) {
|
||||
mOpenFlags = openFlags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds flags to control database access mode
|
||||
*
|
||||
* @param openFlags The new flags to add
|
||||
* @return same builder instance for chaining multiple calls into a single statement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addOpenFlags(@DatabaseOpenFlags int openFlags) {
|
||||
mOpenFlags |= openFlags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes database access mode flags
|
||||
*
|
||||
* @param openFlags Flags to remove
|
||||
* @return same builder instance for chaining multiple calls into a single statement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder removeOpenFlags(@DatabaseOpenFlags int openFlags) {
|
||||
mOpenFlags &= ~openFlags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link #ENABLE_WRITE_AHEAD_LOGGING} flag if {@code enabled} is {@code true},
|
||||
* unsets otherwise
|
||||
* @hide
|
||||
*/
|
||||
public void setWriteAheadLoggingEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
addOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
|
||||
} else {
|
||||
removeOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an optional factory class that is called to instantiate a cursor when query
|
||||
* is called.
|
||||
*
|
||||
* @param cursorFactory instance
|
||||
* @return same builder instance for chaining multiple calls into a single statement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCursorFactory(@Nullable CursorFactory cursorFactory) {
|
||||
mCursorFactory = cursorFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets {@link DatabaseErrorHandler} object to handle db corruption errors
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setErrorHandler(@Nullable DatabaseErrorHandler errorHandler) {
|
||||
mErrorHandler = errorHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link OpenParams} with the options that were previously set
|
||||
* on this builder
|
||||
*/
|
||||
@NonNull
|
||||
public OpenParams build() {
|
||||
return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
|
||||
mLookasideSlotCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = {"OPEN_", "CREATE_", "NO_", "ENABLE_"}, value = {
|
||||
OPEN_READWRITE,
|
||||
OPEN_READONLY,
|
||||
CREATE_IF_NECESSARY,
|
||||
NO_LOCALIZED_COLLATORS,
|
||||
ENABLE_WRITE_AHEAD_LOGGING
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DatabaseOpenFlags {}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,20 @@ public final class SQLiteDatabaseConfiguration {
|
||||
public final ArrayList<SQLiteCustomFunction> customFunctions =
|
||||
new ArrayList<SQLiteCustomFunction>();
|
||||
|
||||
/**
|
||||
* The size in bytes of each lookaside slot
|
||||
*
|
||||
* <p>If negative, the default lookaside configuration will be used
|
||||
*/
|
||||
public int lookasideSlotSize;
|
||||
|
||||
/**
|
||||
* The total number of lookaside memory slots per database connection
|
||||
*
|
||||
* <p>If negative, the default lookaside configuration will be used
|
||||
*/
|
||||
public int lookasideSlotCount;
|
||||
|
||||
/**
|
||||
* Creates a database configuration with the required parameters for opening a
|
||||
* database and default values for all other parameters.
|
||||
@@ -108,6 +122,8 @@ public final class SQLiteDatabaseConfiguration {
|
||||
// Set default values for optional parameters.
|
||||
maxSqlCacheSize = 25;
|
||||
locale = Locale.getDefault();
|
||||
lookasideSlotSize = -1;
|
||||
lookasideSlotCount = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,6 +162,8 @@ public final class SQLiteDatabaseConfiguration {
|
||||
foreignKeyConstraintsEnabled = other.foreignKeyConstraintsEnabled;
|
||||
customFunctions.clear();
|
||||
customFunctions.addAll(other.customFunctions);
|
||||
lookasideSlotSize = other.lookasideSlotSize;
|
||||
lookasideSlotCount = other.lookasideSlotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package android.database.sqlite;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.content.Context;
|
||||
import android.database.DatabaseErrorHandler;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||
import android.os.FileUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@@ -43,24 +47,14 @@ import java.io.File;
|
||||
public abstract class SQLiteOpenHelper {
|
||||
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
|
||||
|
||||
// When true, getReadableDatabase returns a read-only database if it is just being opened.
|
||||
// The database handle is reopened in read/write mode when getWritableDatabase is called.
|
||||
// We leave this behavior disabled in production because it is inefficient and breaks
|
||||
// many applications. For debugging purposes it can be useful to turn on strict
|
||||
// read-only semantics to catch applications that call getReadableDatabase when they really
|
||||
// wanted getWritableDatabase.
|
||||
private static final boolean DEBUG_STRICT_READONLY = false;
|
||||
|
||||
private final Context mContext;
|
||||
private final String mName;
|
||||
private final CursorFactory mFactory;
|
||||
private final int mNewVersion;
|
||||
private final int mMinimumSupportedVersion;
|
||||
|
||||
private SQLiteDatabase mDatabase;
|
||||
private boolean mIsInitializing;
|
||||
private boolean mEnableWriteAheadLogging;
|
||||
private final DatabaseErrorHandler mErrorHandler;
|
||||
private final SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
|
||||
|
||||
/**
|
||||
* Create a helper object to create, open, and/or manage a database.
|
||||
@@ -130,10 +124,12 @@ public abstract class SQLiteOpenHelper {
|
||||
|
||||
mContext = context;
|
||||
mName = name;
|
||||
mFactory = factory;
|
||||
mNewVersion = version;
|
||||
mErrorHandler = errorHandler;
|
||||
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
|
||||
mOpenParamsBuilder = new SQLiteDatabase.OpenParams.Builder();
|
||||
mOpenParamsBuilder.setCursorFactory(factory);
|
||||
mOpenParamsBuilder.setErrorHandler(errorHandler);
|
||||
mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,7 +153,7 @@ public abstract class SQLiteOpenHelper {
|
||||
*/
|
||||
public void setWriteAheadLoggingEnabled(boolean enabled) {
|
||||
synchronized (this) {
|
||||
if (mEnableWriteAheadLogging != enabled) {
|
||||
if (mOpenParamsBuilder.isWriteAheadLoggingEnabled() != enabled) {
|
||||
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
|
||||
if (enabled) {
|
||||
mDatabase.enableWriteAheadLogging();
|
||||
@@ -165,11 +161,35 @@ public abstract class SQLiteOpenHelper {
|
||||
mDatabase.disableWriteAheadLogging();
|
||||
}
|
||||
}
|
||||
mEnableWriteAheadLogging = enabled;
|
||||
mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
|
||||
*
|
||||
* <p>This method should be called from the constructor of the subclass,
|
||||
* before opening the database, since lookaside memory configuration can only be changed
|
||||
* when no connection is using it
|
||||
*
|
||||
* <p>SQLite default settings will be used, if this method isn't called.
|
||||
* Use {@code setLookasideConfig(0,0)} to disable lookaside
|
||||
*
|
||||
* @param slotSize The size in bytes of each lookaside slot.
|
||||
* @param slotCount The total number of lookaside memory slots per database connection.
|
||||
*/
|
||||
public void setLookasideConfig(@IntRange(from = 0) final int slotSize,
|
||||
@IntRange(from = 0) final int slotCount) {
|
||||
synchronized (this) {
|
||||
if (mDatabase != null && mDatabase.isOpen()) {
|
||||
throw new IllegalStateException(
|
||||
"Lookaside memory config cannot be changed after opening the database");
|
||||
}
|
||||
mOpenParamsBuilder.setLookasideConfig(slotSize, slotCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and/or open a database that will be used for reading and writing.
|
||||
* The first time this is called, the database will be opened and
|
||||
@@ -243,27 +263,22 @@ public abstract class SQLiteOpenHelper {
|
||||
db.reopenReadWrite();
|
||||
}
|
||||
} else if (mName == null) {
|
||||
db = SQLiteDatabase.create(null);
|
||||
db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());
|
||||
} else {
|
||||
final String path = mContext.getDatabasePath(mName).getPath();
|
||||
SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();
|
||||
try {
|
||||
if (DEBUG_STRICT_READONLY && !writable) {
|
||||
final String path = mContext.getDatabasePath(mName).getPath();
|
||||
db = SQLiteDatabase.openDatabase(path, mFactory,
|
||||
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
|
||||
} else {
|
||||
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
|
||||
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
|
||||
mFactory, mErrorHandler);
|
||||
}
|
||||
} catch (SQLiteException ex) {
|
||||
db = SQLiteDatabase.openDatabase(path, params);
|
||||
// Keep pre-O-MR1 behavior by resetting file permissions to 660
|
||||
setFilePermissionsForDb(path);
|
||||
} catch (SQLException ex) {
|
||||
if (writable) {
|
||||
throw ex;
|
||||
}
|
||||
Log.e(TAG, "Couldn't open " + mName
|
||||
+ " for writing (will try read-only):", ex);
|
||||
final String path = mContext.getDatabasePath(mName).getPath();
|
||||
db = SQLiteDatabase.openDatabase(path, mFactory,
|
||||
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
|
||||
params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
|
||||
db = SQLiteDatabase.openDatabase(path, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +338,11 @@ public abstract class SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setFilePermissionsForDb(String dbPath) {
|
||||
int perms = FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP;
|
||||
FileUtils.setPermissions(dbPath, perms, -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close any open database object.
|
||||
*/
|
||||
|
||||
@@ -112,7 +112,8 @@ static int sqliteProgressHandlerCallback(void* data) {
|
||||
|
||||
|
||||
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
|
||||
jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
|
||||
jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
|
||||
jint lookasideCnt) {
|
||||
int sqliteFlags;
|
||||
if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
|
||||
sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
||||
@@ -137,6 +138,16 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lookasideSz >= 0 && lookasideCnt >= 0) {
|
||||
int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
|
||||
if (err != SQLITE_OK) {
|
||||
ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
|
||||
throw_sqlite3_exception(env, db, "Cannot set lookaside");
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the database is really read/write when that is what we asked for.
|
||||
if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
|
||||
throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
|
||||
@@ -789,7 +800,7 @@ static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
|
||||
static const JNINativeMethod sMethods[] =
|
||||
{
|
||||
/* name, signature, funcPtr */
|
||||
{ "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J",
|
||||
{ "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
|
||||
(void*)nativeOpen },
|
||||
{ "nativeClose", "(J)V",
|
||||
(void*)nativeClose },
|
||||
|
||||
@@ -18,11 +18,12 @@ package android.database;
|
||||
|
||||
import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
|
||||
import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteDebug;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcel;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.PerformanceTestCase;
|
||||
@@ -40,6 +41,9 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Usage: bit FrameworksCoreTests:android.database.DatabaseGeneralTest
|
||||
*/
|
||||
public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
|
||||
private static final String TAG = "DatabaseGeneralTest";
|
||||
|
||||
@@ -68,7 +72,7 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
mDatabase.close();
|
||||
mDatabaseFile.delete();
|
||||
SQLiteDatabase.deleteDatabase(mDatabaseFile);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@@ -1044,6 +1048,52 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
|
||||
}
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testOpenDatabaseLookasideConfig() {
|
||||
// First check that lookaside is active
|
||||
verifyLookasideStats(false);
|
||||
// Reopen test db with lookaside disabled
|
||||
mDatabase.close();
|
||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
|
||||
.setLookasideConfig(0, 0).build();
|
||||
mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), params);
|
||||
verifyLookasideStats(true);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testOpenParamsSetLookasideConfigValidation() {
|
||||
try {
|
||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
|
||||
.setLookasideConfig(-1, 0).build();
|
||||
fail("Negative slot size should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
|
||||
.setLookasideConfig(0, -10).build();
|
||||
fail("Negative slot count should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
void verifyLookasideStats(boolean expectDisabled) {
|
||||
boolean dbStatFound = false;
|
||||
SQLiteDebug.PagerStats info = SQLiteDebug.getDatabaseInfo();
|
||||
for (SQLiteDebug.DbStats dbStat : info.dbStats) {
|
||||
if (dbStat.dbName.endsWith(mDatabaseFile.getName())) {
|
||||
dbStatFound = true;
|
||||
Log.i(TAG, "Lookaside for " + dbStat.dbName + " " + dbStat.lookaside);
|
||||
if (expectDisabled) {
|
||||
assertTrue("lookaside slots count should be zero", dbStat.lookaside == 0);
|
||||
} else {
|
||||
assertTrue("lookaside slots count should be greater than zero",
|
||||
dbStat.lookaside > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue("No dbstat found for " + mDatabaseFile.getName(), dbStatFound);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testDefaultDatabaseErrorHandler() {
|
||||
DefaultDatabaseErrorHandler errorHandler = new DefaultDatabaseErrorHandler();
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.database;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteDatabaseConfiguration;
|
||||
import android.database.sqlite.SQLiteDebug;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for {@link SQLiteOpenHelper}
|
||||
*
|
||||
* <p>Run with: bit FrameworksCoreTests:android.database.SQLiteOpenHelperTest
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class SQLiteOpenHelperTest {
|
||||
private static final String TAG = "SQLiteOpenHelperTest";
|
||||
|
||||
private TestHelper mTestHelper;
|
||||
private Context mContext;
|
||||
private List<SQLiteOpenHelper> mHelpersToClose;
|
||||
|
||||
private static class TestHelper extends SQLiteOpenHelper {
|
||||
TestHelper(Context context) { // In-memory
|
||||
super(context, null, null, 1);
|
||||
}
|
||||
|
||||
TestHelper(Context context, String name) {
|
||||
super(context, name, null, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = InstrumentationRegistry.getContext();
|
||||
mTestHelper = new TestHelper(mContext, "openhelper_test");
|
||||
mHelpersToClose = new ArrayList<>();
|
||||
mHelpersToClose.add(mTestHelper);
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
for (SQLiteOpenHelper helper : mHelpersToClose) {
|
||||
try {
|
||||
helper.close();
|
||||
if (mTestHelper.getDatabaseName() != null) {
|
||||
SQLiteDatabase.deleteDatabase(
|
||||
mContext.getDatabasePath(mTestHelper.getDatabaseName()));
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
Log.w(TAG, "Error occured when closing db helper " + helper, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookasideDefault() throws Exception {
|
||||
assertNotNull(mTestHelper.getWritableDatabase());
|
||||
verifyLookasideStats(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookasideDisabled() throws Exception {
|
||||
mTestHelper.setLookasideConfig(0, 0);
|
||||
assertNotNull(mTestHelper.getWritableDatabase());
|
||||
verifyLookasideStats(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInMemoryLookasideDisabled() throws Exception {
|
||||
TestHelper memHelper = new TestHelper(mContext);
|
||||
mHelpersToClose.add(memHelper);
|
||||
memHelper.setLookasideConfig(0, 0);
|
||||
assertNotNull(memHelper.getWritableDatabase());
|
||||
verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInMemoryLookasideDefault() throws Exception {
|
||||
TestHelper memHelper = new TestHelper(mContext);
|
||||
mHelpersToClose.add(memHelper);
|
||||
assertNotNull(memHelper.getWritableDatabase());
|
||||
verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLookasideConfigValidation() {
|
||||
try {
|
||||
mTestHelper.setLookasideConfig(-1, 0);
|
||||
fail("Negative slot size should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
mTestHelper.setLookasideConfig(0, -10);
|
||||
fail("Negative slot count should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
mTestHelper.setLookasideConfig(1, 0);
|
||||
fail("Illegal config should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
mTestHelper.setLookasideConfig(0, 1);
|
||||
fail("Illegal config should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyLookasideStats(boolean expectDisabled) {
|
||||
verifyLookasideStats(mTestHelper.getDatabaseName(), expectDisabled);
|
||||
}
|
||||
|
||||
private static void verifyLookasideStats(String dbName, boolean expectDisabled) {
|
||||
boolean dbStatFound = false;
|
||||
SQLiteDebug.PagerStats info = SQLiteDebug.getDatabaseInfo();
|
||||
for (SQLiteDebug.DbStats dbStat : info.dbStats) {
|
||||
if (dbStat.dbName.endsWith(dbName)) {
|
||||
dbStatFound = true;
|
||||
Log.i(TAG, "Lookaside for " + dbStat.dbName + " " + dbStat.lookaside);
|
||||
if (expectDisabled) {
|
||||
assertTrue("lookaside slots count should be zero", dbStat.lookaside == 0);
|
||||
} else {
|
||||
assertTrue("lookaside slots count should be greater than zero",
|
||||
dbStat.lookaside > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue("No dbstat found for " + dbName, dbStatFound);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user