// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/351564777): Remove this and convert code to safer constructs. #pragma allow_unsafe_buffers #endif #include <stddef.h> #include <stdint.h> #include <cstring> #include <string> #include <tuple> #include <vector> #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/memory_mapped_file.h" #include "base/files/scoped_temp_dir.h" #include "base/time/time.h" #include "build/build_config.h" #include "sql/database.h" #include "sql/statement.h" #include "sql/statement_id.h" #include "sql/test/scoped_error_expecter.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" #if BUILDFLAG(IS_APPLE) #include "base/apple/backup_util.h" #endif // Test that certain features are/are-not enabled in our SQLite. namespace sql { namespace { ExecuteWithResult; ExecuteWithResults; } // namespace class SQLiteFeaturesTest : public testing::Test { … }; // Do not include fts1 support, it is not useful, and nobody is // looking at it. TEST_F(SQLiteFeaturesTest, NoFTS1) { … } // Do not include fts2 support, it is not useful, and nobody is // looking at it. TEST_F(SQLiteFeaturesTest, NoFTS2) { … } // fts3 is exposed in WebSQL. TEST_F(SQLiteFeaturesTest, FTS3) { … } // Originally history used fts2, which Chromium patched to treat "foo*" as a // prefix search, though the icu tokenizer would return it as two tokens {"foo", // "*"}. Test that fts3 works correctly. TEST_F(SQLiteFeaturesTest, FTS3_Prefix) { … } // Verify that Chromium's SQLite is compiled with HAVE_USLEEP defined. With // HAVE_USLEEP, SQLite uses usleep() with millisecond granularity. Otherwise it // uses sleep() with second granularity. TEST_F(SQLiteFeaturesTest, UsesUsleep) { … } // Ensure that our SQLite version has working foreign key support with cascade // delete support. TEST_F(SQLiteFeaturesTest, ForeignKeySupport) { … } // Ensure that our SQLite version supports booleans. TEST_F(SQLiteFeaturesTest, BooleanSupport) { … } TEST_F(SQLiteFeaturesTest, IcuEnabled) { … } // Verify that OS file writes are reflected in the memory mapping of a // memory-mapped file. Normally SQLite writes to memory-mapped files using // memcpy(), which should stay consistent. Our SQLite is slightly patched to // mmap read only, then write using OS file writes. If the memory-mapped // version doesn't reflect the OS file writes, SQLite's memory-mapped I/O should // be disabled on this platform using SQLITE_MAX_MMAP_SIZE=0. TEST_F(SQLiteFeaturesTest, Mmap) { … } // Verify that http://crbug.com/248608 is fixed. In this bug, the // compiled regular expression is effectively cached with the prepared // statement, causing errors if the regular expression is rebound. TEST_F(SQLiteFeaturesTest, CachedRegexp) { … } TEST_F(SQLiteFeaturesTest, JsonIsDisabled) { … } TEST_F(SQLiteFeaturesTest, WindowFunctionsAreDisabled) { … } // The "No Isolation Between Operations On The Same Database Connection" section // in https://sqlite.org/isolation.html implies that it's safe to issue multiple // concurrent SELECTs against the same area. // // Chrome code is allowed to rely on this guarantee. So, we test for it here, to // catch any regressions introduced by SQLite upgrades. TEST_F(SQLiteFeaturesTest, ConcurrentSelects) { … } // The "No Isolation Between Operations On The Same Database Connection" section // in https://sqlite.org/isolation.html states that it's safe to DELETE a row // that was just returned by sqlite_step() executing a SELECT statement. // // Chrome code is allowed to rely on this guarantee. So, we test for it here, to // catch any regressions introduced by SQLite upgrades. TEST_F(SQLiteFeaturesTest, DeleteCurrentlySelectedRow) { … } // The "No Isolation Between Operations On The Same Database Connection" section // in https://sqlite.org/isolation.html states that it's safe to DELETE a row // that was previously by sqlite_step() executing a SELECT statement. // // Chrome code is allowed to rely on this guarantee. So, we test for it here, to // catch any regressions introduced by SQLite upgrades. TEST_F(SQLiteFeaturesTest, DeletePreviouslySelectedRows) { … } // The "No Isolation Between Operations On The Same Database Connection" section // in https://sqlite.org/isolation.html states that it's safe to DELETE a row // while a SELECT statement executes, but the DELETEd row may or may not show up // in the SELECT results. (See the test above for a case where the DELETEd row // is guaranteed to now show up in the SELECT results.) // // This seems to imply that DELETEing from a table that is not read by the // concurrent SELECT statement is safe and well-defined, as the DELETEd row(s) // cannot possibly show up in the SELECT results. // // Chrome features are allowed to rely on the implication above, because it // comes in very handy for DELETEing data across multiple tables. This test // ensures that our assumption remains valid. TEST_F(SQLiteFeaturesTest, DeleteWhileSelectingFromDifferentTable) { … } // The "No Isolation Between Operations On The Same Database Connection" section // in https://sqlite.org/isolation.html states that it's possible to INSERT in // a table while concurrently executing a SELECT statement reading from it, but // it's undefined whether the row will show up in the SELECT statement's results // or not. // // Given this ambiguity, Chrome code is not allowed to INSERT in the same table // as a concurrent SELECT. However, it is allowed to INSERT in a table which is // not covered by SELECT, because this greatly simplifes migrations. So, we test // the ability to INSERT in a table while SELECTing from another table, to // catch any regressions introduced by SQLite upgrades. TEST_F(SQLiteFeaturesTest, InsertWhileSelectingFromDifferentTable) { … } #if BUILDFLAG(IS_APPLE) // If a database file is marked to be excluded from backups, verify that journal // files are also excluded. TEST_F(SQLiteFeaturesTest, TimeMachine) { ASSERT_TRUE(db_.Execute("CREATE TABLE t (id INTEGER PRIMARY KEY)")); db_.Close(); base::FilePath journal_path = sql::Database::JournalPath(db_path_); ASSERT_TRUE(base::PathExists(db_path_)); ASSERT_TRUE(base::PathExists(journal_path)); // Not excluded to start. EXPECT_FALSE(base::apple::GetBackupExclusion(db_path_)); EXPECT_FALSE(base::apple::GetBackupExclusion(journal_path)); // Exclude the main database file. EXPECT_TRUE(base::apple::SetBackupExclusion(db_path_)); EXPECT_TRUE(base::apple::GetBackupExclusion(db_path_)); EXPECT_FALSE(base::apple::GetBackupExclusion(journal_path)); EXPECT_TRUE(db_.Open(db_path_)); ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (1)")); EXPECT_TRUE(base::apple::GetBackupExclusion(db_path_)); EXPECT_TRUE(base::apple::GetBackupExclusion(journal_path)); // TODO(shess): In WAL mode this will touch -wal and -shm files. -shm files // could be always excluded. } #endif #if !BUILDFLAG(IS_FUCHSIA) // SQLite WAL mode defaults to checkpointing the WAL on close. This would push // additional work into Chromium shutdown. Verify that SQLite supports a config // option to not checkpoint on close. TEST_F(SQLiteFeaturesTest, WALNoClose) { … } #endif } // namespace sql