Loading core/java/android/database/sqlite/SQLiteDatabase.java +33 −5 Original line number Diff line number Diff line Loading @@ -236,15 +236,21 @@ public final class SQLiteDatabase extends SQLiteClosable { * * {@more} Note that the value of this flag is 0, so it is the default. */ public static final int OPEN_READWRITE = 0x00000000; // update native code if changing // LINT.IfChange public static final int OPEN_READWRITE = 0x00000000; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database for reading only. * This is the only reliable way to open a database if the disk may be full. */ public static final int OPEN_READONLY = 0x00000001; // update native code if changing // LINT.IfChange public static final int OPEN_READONLY = 0x00000001; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing // LINT.IfChange private static final int OPEN_READ_MASK = 0x00000001; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database without support for Loading @@ -254,13 +260,31 @@ public final class SQLiteDatabase extends SQLiteClosable { * You must be consistent when using this flag to use the setting the database was * created with. If this is set, {@link #setLocale} will do nothing. */ public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing // LINT.IfChange public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open a database, disallowing double-quoted * strings. * * This causes sqlite to reject SQL statements with double-quoted string literals. String * literals must be enclosed in single quotes; double-quotes are reserved for identifiers like * column names. * See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted * @hide */ // LINT.IfChange public static final int NO_DOUBLE_QUOTED_STRS = 0x00000020; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to create the database file if it does not * already exist. */ public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing // LINT.IfChange public static final int CREATE_IF_NECESSARY = 0x10000000; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database file with Loading Loading @@ -490,6 +514,9 @@ public final class SQLiteDatabase extends SQLiteClosable { if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) { mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL; } if (SQLiteDebug.NoPreloadHolder.NO_DOUBLE_QUOTED_STRS) { mConfigurationLocked.openFlags |= NO_DOUBLE_QUOTED_STRS; } mConfigurationLocked.journalMode = journalMode; mConfigurationLocked.syncMode = syncMode; } Loading Loading @@ -3275,6 +3302,7 @@ public final class SQLiteDatabase extends SQLiteClosable { OPEN_READONLY, CREATE_IF_NECESSARY, NO_LOCALIZED_COLLATORS, NO_DOUBLE_QUOTED_STRS, ENABLE_WRITE_AHEAD_LOGGING }) @Retention(RetentionPolicy.SOURCE) Loading core/java/android/database/sqlite/SQLiteDebug.java +9 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ public final class SQLiteDebug { public static final boolean DEBUG_SQL_TIME = Log.isLoggable("SQLiteTime", Log.VERBOSE); /** * True to enable database performance testing instrumentation. */ Loading @@ -83,6 +82,15 @@ public final class SQLiteDebug { */ public static final boolean DEBUG_LOG_DETAILED = Build.IS_DEBUGGABLE && SystemProperties.getBoolean("db.log.detailed", false); /** * Whether to accept double-quoted strings in SQL statements. Double-quoted strings are a * syntax error but are accepted by sqlite in compatibility mode (the default). If the * property is set to true, double-quoted strings will be treated by sqlite as a syntax * error. */ public static final boolean NO_DOUBLE_QUOTED_STRS = SystemProperties.getBoolean("debug.sqlite.no_double_quoted_strs", false); } private SQLiteDebug() { Loading core/jni/android_database_SQLiteConnection.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -70,11 +70,14 @@ struct SQLiteConnection { // Open flags. // Must be kept in sync with the constants defined in SQLiteDatabase.java. enum { // LINT.IfChange OPEN_READWRITE = 0x00000000, OPEN_READONLY = 0x00000001, OPEN_READ_MASK = 0x00000001, NO_LOCALIZED_COLLATORS = 0x00000010, NO_DOUBLE_QUOTED_STRS = 0x00000020, CREATE_IF_NECESSARY = 0x10000000, // LINT.ThenChange(/core/java/android/database/sqlite/SQLiteDatabase.java) }; sqlite3* const db; Loading Loading @@ -156,6 +159,18 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla } } // Disallow double-quoted string literals if the proper flag is set. if ((openFlags & SQLiteConnection::NO_DOUBLE_QUOTED_STRS) != 0) { void *setting = 0; int err = 0; if ((err = sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, setting)) != SQLITE_OK) { ALOGE("failed to configure SQLITE_DBCONFIG_DQS_DDL: %d", err); } if ((err = sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, setting)) != SQLITE_OK) { ALOGE("failed to configure SQLITE_DBCONFIG_DQS_DML: %d", err); } } // 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."); Loading core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java +54 −0 Original line number Diff line number Diff line Loading @@ -538,4 +538,58 @@ public class SQLiteDatabaseTest { assertEquals(1, db.mConnection.size()); } // Create and open the database, allowing or disallowing double-quoted strings. private void createDatabase(boolean noDoubleQuotedStrs) throws Exception { // The open-flags that do not change in this test. int flags = SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.OPEN_READWRITE; // The flag to be tested. int flagUnderTest = SQLiteDatabase.NO_DOUBLE_QUOTED_STRS; if (noDoubleQuotedStrs) { flags |= flagUnderTest; } else { flags &= ~flagUnderTest; } mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), null, flags, null); } /** * This test verifies that the NO_DOUBLE_QUOTED_STRS flag works as expected when opening a * database. This does not test that the flag is initialized as expected from the system * properties. */ @Test public void testNoDoubleQuotedStrings() throws Exception { closeAndDeleteDatabase(); createDatabase(/* noDoubleQuotedStrs */ false); mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (t text);"); // Insert a value in double-quotes. This is invalid but accepted. mDatabase.execSQL("INSERT INTO t1 (t) VALUES (\"foo\")"); } finally { mDatabase.endTransaction(); } closeAndDeleteDatabase(); createDatabase(/* noDoubleQuotedStrs */ true); mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (t text);"); try { // Insert a value in double-quotes. This is invalid and must throw. mDatabase.execSQL("INSERT INTO t1 (t) VALUES (\"foo\")"); fail("expected an exception"); } catch (SQLiteException e) { assertTrue(e.toString().contains("no such column")); } } finally { mDatabase.endTransaction(); } closeAndDeleteDatabase(); } } Loading
core/java/android/database/sqlite/SQLiteDatabase.java +33 −5 Original line number Diff line number Diff line Loading @@ -236,15 +236,21 @@ public final class SQLiteDatabase extends SQLiteClosable { * * {@more} Note that the value of this flag is 0, so it is the default. */ public static final int OPEN_READWRITE = 0x00000000; // update native code if changing // LINT.IfChange public static final int OPEN_READWRITE = 0x00000000; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database for reading only. * This is the only reliable way to open a database if the disk may be full. */ public static final int OPEN_READONLY = 0x00000001; // update native code if changing // LINT.IfChange public static final int OPEN_READONLY = 0x00000001; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing // LINT.IfChange private static final int OPEN_READ_MASK = 0x00000001; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database without support for Loading @@ -254,13 +260,31 @@ public final class SQLiteDatabase extends SQLiteClosable { * You must be consistent when using this flag to use the setting the database was * created with. If this is set, {@link #setLocale} will do nothing. */ public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing // LINT.IfChange public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open a database, disallowing double-quoted * strings. * * This causes sqlite to reject SQL statements with double-quoted string literals. String * literals must be enclosed in single quotes; double-quotes are reserved for identifiers like * column names. * See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted * @hide */ // LINT.IfChange public static final int NO_DOUBLE_QUOTED_STRS = 0x00000020; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to create the database file if it does not * already exist. */ public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing // LINT.IfChange public static final int CREATE_IF_NECESSARY = 0x10000000; // LINT.ThenChange(/core/jni/android_database_SQLiteConnection.cpp) /** * Open flag: Flag for {@link #openDatabase} to open the database file with Loading Loading @@ -490,6 +514,9 @@ public final class SQLiteDatabase extends SQLiteClosable { if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) { mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL; } if (SQLiteDebug.NoPreloadHolder.NO_DOUBLE_QUOTED_STRS) { mConfigurationLocked.openFlags |= NO_DOUBLE_QUOTED_STRS; } mConfigurationLocked.journalMode = journalMode; mConfigurationLocked.syncMode = syncMode; } Loading Loading @@ -3275,6 +3302,7 @@ public final class SQLiteDatabase extends SQLiteClosable { OPEN_READONLY, CREATE_IF_NECESSARY, NO_LOCALIZED_COLLATORS, NO_DOUBLE_QUOTED_STRS, ENABLE_WRITE_AHEAD_LOGGING }) @Retention(RetentionPolicy.SOURCE) Loading
core/java/android/database/sqlite/SQLiteDebug.java +9 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ public final class SQLiteDebug { public static final boolean DEBUG_SQL_TIME = Log.isLoggable("SQLiteTime", Log.VERBOSE); /** * True to enable database performance testing instrumentation. */ Loading @@ -83,6 +82,15 @@ public final class SQLiteDebug { */ public static final boolean DEBUG_LOG_DETAILED = Build.IS_DEBUGGABLE && SystemProperties.getBoolean("db.log.detailed", false); /** * Whether to accept double-quoted strings in SQL statements. Double-quoted strings are a * syntax error but are accepted by sqlite in compatibility mode (the default). If the * property is set to true, double-quoted strings will be treated by sqlite as a syntax * error. */ public static final boolean NO_DOUBLE_QUOTED_STRS = SystemProperties.getBoolean("debug.sqlite.no_double_quoted_strs", false); } private SQLiteDebug() { Loading
core/jni/android_database_SQLiteConnection.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -70,11 +70,14 @@ struct SQLiteConnection { // Open flags. // Must be kept in sync with the constants defined in SQLiteDatabase.java. enum { // LINT.IfChange OPEN_READWRITE = 0x00000000, OPEN_READONLY = 0x00000001, OPEN_READ_MASK = 0x00000001, NO_LOCALIZED_COLLATORS = 0x00000010, NO_DOUBLE_QUOTED_STRS = 0x00000020, CREATE_IF_NECESSARY = 0x10000000, // LINT.ThenChange(/core/java/android/database/sqlite/SQLiteDatabase.java) }; sqlite3* const db; Loading Loading @@ -156,6 +159,18 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla } } // Disallow double-quoted string literals if the proper flag is set. if ((openFlags & SQLiteConnection::NO_DOUBLE_QUOTED_STRS) != 0) { void *setting = 0; int err = 0; if ((err = sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, setting)) != SQLITE_OK) { ALOGE("failed to configure SQLITE_DBCONFIG_DQS_DDL: %d", err); } if ((err = sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, setting)) != SQLITE_OK) { ALOGE("failed to configure SQLITE_DBCONFIG_DQS_DML: %d", err); } } // 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."); Loading
core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java +54 −0 Original line number Diff line number Diff line Loading @@ -538,4 +538,58 @@ public class SQLiteDatabaseTest { assertEquals(1, db.mConnection.size()); } // Create and open the database, allowing or disallowing double-quoted strings. private void createDatabase(boolean noDoubleQuotedStrs) throws Exception { // The open-flags that do not change in this test. int flags = SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.OPEN_READWRITE; // The flag to be tested. int flagUnderTest = SQLiteDatabase.NO_DOUBLE_QUOTED_STRS; if (noDoubleQuotedStrs) { flags |= flagUnderTest; } else { flags &= ~flagUnderTest; } mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), null, flags, null); } /** * This test verifies that the NO_DOUBLE_QUOTED_STRS flag works as expected when opening a * database. This does not test that the flag is initialized as expected from the system * properties. */ @Test public void testNoDoubleQuotedStrings() throws Exception { closeAndDeleteDatabase(); createDatabase(/* noDoubleQuotedStrs */ false); mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (t text);"); // Insert a value in double-quotes. This is invalid but accepted. mDatabase.execSQL("INSERT INTO t1 (t) VALUES (\"foo\")"); } finally { mDatabase.endTransaction(); } closeAndDeleteDatabase(); createDatabase(/* noDoubleQuotedStrs */ true); mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (t text);"); try { // Insert a value in double-quotes. This is invalid and must throw. mDatabase.execSQL("INSERT INTO t1 (t) VALUES (\"foo\")"); fail("expected an exception"); } catch (SQLiteException e) { assertTrue(e.toString().contains("no such column")); } } finally { mDatabase.endTransaction(); } closeAndDeleteDatabase(); } }