diff --git a/api/current.txt b/api/current.txt
index ff74ce8b43dc5..d7067549fc7cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13391,6 +13391,7 @@ package android.database.sqlite {
method public void disableWriteAheadLogging();
method public boolean enableWriteAheadLogging();
method public void endTransaction();
+ method public void execPerConnectionSQL(@NonNull String, @Nullable Object[]) throws android.database.SQLException;
method public void execSQL(String) throws android.database.SQLException;
method public void execSQL(String, Object[]) throws android.database.SQLException;
method public static String findEditTable(String);
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 796cfdce2c0dd..bcb3934a5b08e 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -28,6 +28,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.util.LruCache;
+import android.util.Pair;
import android.util.Printer;
import dalvik.system.BlockGuard;
@@ -230,6 +231,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
setAutoCheckpointInterval();
setLocaleFromConfiguration();
setCustomFunctionsFromConfiguration();
+ executePerConnectionSqlFromConfiguration(0);
}
private void dispose(boolean finalized) {
@@ -468,6 +470,24 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
}
+ private void executePerConnectionSqlFromConfiguration(int startIndex) {
+ for (int i = startIndex; i < mConfiguration.perConnectionSql.size(); i++) {
+ final Pair
+ * This statement will be immediately executed on all existing connections,
+ * and will be automatically executed on all future connections.
+ *
+ * Some example usages are changes like {@code PRAGMA trusted_schema=OFF} or
+ * functions like {@code SELECT icu_load_collation()}. If you execute these
+ * statements using {@link #execSQL} then they will only apply to a single
+ * database connection; using this method will ensure that they are
+ * uniformly applied to all current and future connections.
+ *
+ * @param sql The SQL statement to be executed. Multiple statements
+ * separated by semicolons are not supported.
+ * @param bindArgs The arguments that should be bound to the SQL statement.
+ */
+ public void execPerConnectionSQL(@NonNull String sql, @Nullable Object[] bindArgs)
+ throws SQLException {
+ Objects.requireNonNull(sql);
+
+ synchronized (mLock) {
+ throwIfNotOpenLocked();
+
+ final int index = mConfigurationLocked.perConnectionSql.size();
+ mConfigurationLocked.perConnectionSql.add(Pair.create(sql, bindArgs));
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.perConnectionSql.remove(index);
+ throw ex;
+ }
+ }
+ }
+
/**
* Gets the database version.
*
@@ -1788,6 +1822,12 @@ public final class SQLiteDatabase extends SQLiteClosable {
* using "PRAGMA journal_mode'
+ * Note that {@code PRAGMA} values which apply on a per-connection basis
+ * should not be configured using this method; you should instead
+ * use {@link #execPerConnectionSQL} to ensure that they are uniformly
+ * applied to all current and future connections.
+ *
+ * Note that {@code PRAGMA} values which apply on a per-connection basis + * should not be configured using this method; you should instead + * use {@link #execPerConnectionSQL} to ensure that they are uniformly + * applied to all current and future connections. + *
* * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are * not supported. diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index b11942abe0c7b..21c21c902fed4 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -18,9 +18,10 @@ package android.database.sqlite; import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; +import android.util.Pair; +import java.util.ArrayList; import java.util.Locale; -import java.util.Map; import java.util.function.BinaryOperator; import java.util.function.UnaryOperator; import java.util.regex.Pattern; @@ -101,6 +102,11 @@ public final class SQLiteDatabaseConfiguration { public final ArrayMap