summaryrefslogtreecommitdiffstats
path: root/core/java/android/database
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-03-23 14:38:06 -0700
committerJeff Brown <jeffbrown@google.com>2012-03-23 14:49:39 -0700
commit96496adb611ced49ed1c2c778c616d1f8a5d0e6b (patch)
tree1b9a6dc212632c5514a0b914bafedcaed899ba98 /core/java/android/database
parent47847f3f4dcf2a0dbea0bc0e4f02528e21d37a88 (diff)
downloadframeworks_base-96496adb611ced49ed1c2c778c616d1f8a5d0e6b.zip
frameworks_base-96496adb611ced49ed1c2c778c616d1f8a5d0e6b.tar.gz
frameworks_base-96496adb611ced49ed1c2c778c616d1f8a5d0e6b.tar.bz2
Provide an API for enabling foreign key constraints.
Also provide a lifecycle method on SQLiteOpenHelper so that applications can configure things like this before the onCreate, onUpgrade, onDowngrade and onOpen callbacks run. Change-Id: If3d1396720bd2e032dd9e034733fb1ff9a9733dd
Diffstat (limited to 'core/java/android/database')
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java18
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java14
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java47
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java8
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java42
5 files changed, 127 insertions, 2 deletions
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index e999316..254f652 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -211,6 +211,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
setPageSize();
+ setForeignKeyModeFromConfiguration();
setWalModeFromConfiguration();
setJournalSizeLimit();
setAutoCheckpointInterval();
@@ -267,6 +268,16 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
}
+ private void setForeignKeyModeFromConfiguration() {
+ if (!mIsReadOnlyConnection) {
+ final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0;
+ long value = executeForLong("PRAGMA foreign_keys", null, null);
+ if (value != newValue) {
+ execute("PRAGMA foreign_keys=" + newValue, null, null);
+ }
+ }
+ }
+
private void setWalModeFromConfiguration() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
@@ -389,6 +400,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
// Remember what changed.
+ boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
+ != mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
& SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
@@ -399,6 +412,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
// Update prepared statement cache size.
mPreparedStatementCache.resize(configuration.maxSqlCacheSize);
+ // Update foreign key mode.
+ if (foreignKeyModeChanged) {
+ setForeignKeyModeFromConfiguration();
+ }
+
// Update WAL.
if (walModeChanged) {
setWalModeFromConfiguration();
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 0538ce4..5c8e38b 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -277,6 +277,20 @@ public final class SQLiteConnectionPool implements Closeable {
assert mAvailableNonPrimaryConnections.isEmpty();
}
+ boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
+ != mConfiguration.foreignKeyConstraintsEnabled;
+ if (foreignKeyModeChanged) {
+ // Foreign key constraints can only be changed if there are no transactions
+ // in progress. To make this clear, we throw an exception if there are
+ // any acquired connections.
+ if (!mAcquiredConnections.isEmpty()) {
+ throw new IllegalStateException("Foreign Key Constraints cannot "
+ + "be enabled or disabled while there are transactions in "
+ + "progress. Finish all transactions and release all active "
+ + "database connections first.");
+ }
+ }
+
if (mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
// we have no choice but to close the primary connection beforehand
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 049a615..7bd0c8d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1793,6 +1793,53 @@ public final class SQLiteDatabase extends SQLiteClosable {
}
/**
+ * Sets whether foreign key constraints are enabled for the database.
+ * <p>
+ * By default, foreign key constraints are not enforced by the database.
+ * This method allows an application to enable foreign key constraints.
+ * It must be called each time the database is opened to ensure that foreign
+ * key constraints are enabled for the session.
+ * </p><p>
+ * A good time to call this method is right after calling {@link #openOrCreateDatabase}
+ * or in the {@link SQLiteOpenHelper#onConfigure} callback.
+ * </p><p>
+ * When foreign key constraints are disabled, the database does not check whether
+ * changes to the database will violate foreign key constraints. Likewise, when
+ * foreign key constraints are disabled, the database will not execute cascade
+ * delete or update triggers. As a result, it is possible for the database
+ * state to become inconsistent. To perform a database integrity check,
+ * call {@link #isDatabaseIntegrityOk}.
+ * </p><p>
+ * This method must not be called while a transaction is in progress.
+ * </p><p>
+ * See also <a href="http://sqlite.org/foreignkeys.html">SQLite Foreign Key Constraints</a>
+ * for more details about foreign key constraint support.
+ * </p>
+ *
+ * @param enable True to enable foreign key constraints, false to disable them.
+ *
+ * @throws IllegalStateException if the are transactions is in progress
+ * when this method is called.
+ */
+ public void setForeignKeyConstraintsEnabled(boolean enable) {
+ synchronized (mLock) {
+ throwIfNotOpenLocked();
+
+ if (mConfigurationLocked.foreignKeyConstraintsEnabled == enable) {
+ return;
+ }
+
+ mConfigurationLocked.foreignKeyConstraintsEnabled = enable;
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.foreignKeyConstraintsEnabled = !enable;
+ throw ex;
+ }
+ }
+ }
+
+ /**
* This method enables parallel execution of queries from multiple threads on the
* same database. It does this by opening multiple connections to the database
* and using a different database connection for each query. The database
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 123c2c6..549ab90 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -77,6 +77,13 @@ public final class SQLiteDatabaseConfiguration {
public Locale locale;
/**
+ * True if foreign key constraints are enabled.
+ *
+ * Default is false.
+ */
+ public boolean foreignKeyConstraintsEnabled;
+
+ /**
* The custom functions to register.
*/
public final ArrayList<SQLiteCustomFunction> customFunctions =
@@ -136,6 +143,7 @@ public final class SQLiteDatabaseConfiguration {
openFlags = other.openFlags;
maxSqlCacheSize = other.maxSqlCacheSize;
locale = other.locale;
+ foreignKeyConstraintsEnabled = other.foreignKeyConstraintsEnabled;
customFunctions.clear();
customFunctions.addAll(other.customFunctions);
}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index fe37b8f..431eca2 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -237,6 +237,8 @@ public abstract class SQLiteOpenHelper {
}
}
+ onConfigure(db);
+
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
@@ -261,6 +263,7 @@ public abstract class SQLiteOpenHelper {
db.endTransaction();
}
}
+
onOpen(db);
if (db.isReadOnly()) {
@@ -290,6 +293,25 @@ public abstract class SQLiteOpenHelper {
}
/**
+ * Called when the database connection is being configured, to enable features
+ * such as write-ahead logging or foreign key support.
+ * <p>
+ * This method is called before {@link #onCreate}, {@link #onUpgrade},
+ * {@link #onDowngrade}, or {@link #onOpen} are called. It should not modify
+ * the database except to configure the database connection as required.
+ * </p><p>
+ * This method should only call methods that configure the parameters of the
+ * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
+ * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
+ * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
+ * or executing PRAGMA statements.
+ * </p>
+ *
+ * @param db The database.
+ */
+ public void onConfigure(SQLiteDatabase db) {}
+
+ /**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
@@ -302,11 +324,16 @@ public abstract class SQLiteOpenHelper {
* should use this method to drop tables, add tables, or do anything else it
* needs to upgrade to the new schema version.
*
- * <p>The SQLite ALTER TABLE documentation can be found
+ * <p>
+ * The SQLite ALTER TABLE documentation can be found
* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
* you can use ALTER TABLE to rename the old table, then create the new table and then
* populate the new table with the contents of the old table.
+ * </p><p>
+ * This method executes within a transaction. If an exception is thrown, all changes
+ * will automatically be rolled back.
+ * </p>
*
* @param db The database.
* @param oldVersion The old database version.
@@ -316,11 +343,16 @@ public abstract class SQLiteOpenHelper {
/**
* Called when the database needs to be downgraded. This is strictly similar to
- * onUpgrade() method, but is called whenever current version is newer than requested one.
+ * {@link #onUpgrade} method, but is called whenever current version is newer than requested one.
* However, this method is not abstract, so it is not mandatory for a customer to
* implement it. If not overridden, default implementation will reject downgrade and
* throws SQLiteException
*
+ * <p>
+ * This method executes within a transaction. If an exception is thrown, all changes
+ * will automatically be rolled back.
+ * </p>
+ *
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
@@ -334,6 +366,12 @@ public abstract class SQLiteOpenHelper {
* Called when the database has been opened. The implementation
* should check {@link SQLiteDatabase#isReadOnly} before updating the
* database.
+ * <p>
+ * This method is called after the database connection has been configured
+ * and after the database schema has been created, upgraded or downgraded as necessary.
+ * If the database connection must be configured in some way before the schema
+ * is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
+ * </p>
*
* @param db The database.
*/