summaryrefslogtreecommitdiff
path: root/chromium/sql
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 13:57:45 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-19 13:44:40 +0000
commit6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch)
treeb87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/sql
parentec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff)
downloadqtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/sql')
-rw-r--r--chromium/sql/OWNERS3
-rw-r--r--chromium/sql/connection.cc9
-rw-r--r--chromium/sql/connection.h1
-rw-r--r--chromium/sql/connection_unittest.cc36
-rw-r--r--chromium/sql/sqlite_features_unittest.cc78
5 files changed, 106 insertions, 21 deletions
diff --git a/chromium/sql/OWNERS b/chromium/sql/OWNERS
index 9a8c2d281de..a4209042eed 100644
--- a/chromium/sql/OWNERS
+++ b/chromium/sql/OWNERS
@@ -1,2 +1,5 @@
michaeln@chromium.org
pwnall@chromium.org
+
+# TEAM: storage-dev@chromium.org
+# COMPONENT: Blink>Storage
diff --git a/chromium/sql/connection.cc b/chromium/sql/connection.cc
index 0511e11b5c5..c80758f3d6b 100644
--- a/chromium/sql/connection.cc
+++ b/chromium/sql/connection.cc
@@ -1112,6 +1112,15 @@ bool Connection::Raze() {
// page_size" can be used to query such a database.
ScopedWritableSchema writable_schema(db_);
+#if defined(OS_WIN)
+ // On Windows, truncate silently fails when applied to memory-mapped files.
+ // Disable memory-mapping so that the truncate succeeds. Note that other
+ // connections may have memory-mapped the file, so this may not entirely
+ // prevent the problem.
+ // [Source: <https://sqlite.org/mmap.html> plus experiments.]
+ ignore_result(Execute("PRAGMA mmap_size = 0"));
+#endif
+
const char* kMain = "main";
int rc = BackupDatabase(null_db.db_, db_, kMain);
UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase",rc);
diff --git a/chromium/sql/connection.h b/chromium/sql/connection.h
index 639c333ed4d..838d552cdfd 100644
--- a/chromium/sql/connection.h
+++ b/chromium/sql/connection.h
@@ -527,6 +527,7 @@ class SQL_EXPORT Connection {
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, GetAppropriateMmapSizeAltStatus);
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, OnMemoryDump);
FRIEND_TEST_ALL_PREFIXES(SQLConnectionTest, RegisterIntentToUpload);
+ FRIEND_TEST_ALL_PREFIXES(SQLiteFeaturesTest, WALNoClose);
// Internal initialize function used by both Init and InitInMemory. The file
// name is always 8 bits since we want to use the 8-bit version of
diff --git a/chromium/sql/connection_unittest.cc b/chromium/sql/connection_unittest.cc
index 6ac4f8bc12d..4ee8b0288a3 100644
--- a/chromium/sql/connection_unittest.cc
+++ b/chromium/sql/connection_unittest.cc
@@ -854,6 +854,42 @@ TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) {
// closely match real life. That would also allow testing
// RazeWithTimeout().
+// On Windows, truncate silently fails against a memory-mapped file. One goal
+// of Raze() is to truncate the file to remove blocks which generate I/O errors.
+// Test that Raze() turns off memory mapping so that the file is truncated.
+// [This would not cover the case of multiple connections where one of the other
+// connections is memory-mapped. That is infrequent in Chromium.]
+TEST_F(SQLConnectionTest, RazeTruncate) {
+ // The empty database has 0 or 1 pages. Raze() should leave it with exactly 1
+ // page. Not checking directly because auto_vacuum on Android adds a freelist
+ // page.
+ ASSERT_TRUE(db().Raze());
+ int64_t expected_size;
+ ASSERT_TRUE(base::GetFileSize(db_path(), &expected_size));
+ ASSERT_GT(expected_size, 0);
+
+ // Cause the database to take a few pages.
+ const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+ ASSERT_TRUE(db().Execute(kCreateSql));
+ for (size_t i = 0; i < 24; ++i) {
+ ASSERT_TRUE(
+ db().Execute("INSERT INTO foo (value) VALUES (randomblob(1024))"));
+ }
+ int64_t db_size;
+ ASSERT_TRUE(base::GetFileSize(db_path(), &db_size));
+ ASSERT_GT(db_size, expected_size);
+
+ // Make a query covering most of the database file to make sure that the
+ // blocks are actually mapped into memory. Empirically, the truncate problem
+ // doesn't seem to happen if no blocks are mapped.
+ EXPECT_EQ("24576",
+ ExecuteWithResult(&db(), "SELECT SUM(LENGTH(value)) FROM foo"));
+
+ ASSERT_TRUE(db().Raze());
+ ASSERT_TRUE(base::GetFileSize(db_path(), &db_size));
+ ASSERT_EQ(expected_size, db_size);
+}
+
#if defined(OS_ANDROID)
TEST_F(SQLConnectionTest, SetTempDirForSQL) {
diff --git a/chromium/sql/sqlite_features_unittest.cc b/chromium/sql/sqlite_features_unittest.cc
index 0f124af3c50..88f7802fc02 100644
--- a/chromium/sql/sqlite_features_unittest.cc
+++ b/chromium/sql/sqlite_features_unittest.cc
@@ -32,8 +32,12 @@
// Test that certain features are/are-not enabled in our SQLite.
+namespace sql {
namespace {
+using sql::test::ExecuteWithResult;
+using sql::test::ExecuteWithResults;
+
void CaptureErrorCallback(int* error_pointer, std::string* sql_text,
int error, sql::Statement* stmt) {
*error_pointer = error;
@@ -41,6 +45,8 @@ void CaptureErrorCallback(int* error_pointer, std::string* sql_text,
*sql_text = text ? text : "no statement available";
}
+} // namespace
+
class SQLiteFeaturesTest : public sql::SQLTestBase {
public:
SQLiteFeaturesTest() : error_(SQLITE_OK) {}
@@ -102,10 +108,8 @@ TEST_F(SQLiteFeaturesTest, FTS3_Prefix) {
ASSERT_TRUE(db().Execute("INSERT INTO foo (x) VALUES ('test')"));
- sql::Statement s(db().GetUniqueStatement(
- "SELECT x FROM foo WHERE x MATCH 'te*'"));
- ASSERT_TRUE(s.Step());
- EXPECT_EQ("test", s.ColumnString(0));
+ EXPECT_EQ("test",
+ ExecuteWithResult(&db(), "SELECT x FROM foo WHERE x MATCH 'te*'"));
}
#endif
@@ -118,10 +122,9 @@ TEST_F(SQLiteFeaturesTest, UsesUsleep) {
sqlite3_sleep(1);
base::TimeDelta delta = base::TimeTicks::Now() - before;
- // It is not impossible for this to be over 1000 if things are compiled the
- // right way. But it is very unlikely, most platforms seem to be around
- // <TBD>.
- LOG(ERROR) << "Milliseconds: " << delta.InMilliseconds();
+ // It is not impossible for this to be over 1000 if things are compiled
+ // correctly, but that is very unlikely. Most platforms seem to be exactly
+ // 1ms, with the rest at 2ms, and the worst observed cases was ASAN at 7ms.
EXPECT_LT(delta.InMilliseconds(), 1000);
}
#endif
@@ -135,28 +138,29 @@ TEST_F(SQLiteFeaturesTest, ForeignKeySupport) {
"CREATE TABLE children ("
" id INTEGER PRIMARY KEY,"
" pid INTEGER NOT NULL REFERENCES parents(id) ON DELETE CASCADE)"));
+ const char kSelectParents[] = "SELECT * FROM parents ORDER BY id";
+ const char kSelectChildren[] = "SELECT * FROM children ORDER BY id";
// Inserting without a matching parent should fail with constraint violation.
// Mask off any extended error codes for USE_SYSTEM_SQLITE.
- int insertErr = db().ExecuteAndReturnErrorCode(
- "INSERT INTO children VALUES (10, 1)");
- EXPECT_EQ(SQLITE_CONSTRAINT, (insertErr&0xff));
-
- size_t rows;
- EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows));
- EXPECT_EQ(0u, rows);
+ EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParents));
+ const int insert_error =
+ db().ExecuteAndReturnErrorCode("INSERT INTO children VALUES (10, 1)");
+ EXPECT_EQ(SQLITE_CONSTRAINT, (insert_error & 0xff));
+ EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildren));
// Inserting with a matching parent should work.
ASSERT_TRUE(db().Execute("INSERT INTO parents VALUES (1)"));
+ EXPECT_EQ("1", ExecuteWithResults(&db(), kSelectParents, "|", "\n"));
EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (11, 1)"));
EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (12, 1)"));
- EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows));
- EXPECT_EQ(2u, rows);
+ EXPECT_EQ("11|1\n12|1",
+ ExecuteWithResults(&db(), kSelectChildren, "|", "\n"));
- // Deleting the parent should cascade, i.e., delete the children as well.
+ // Deleting the parent should cascade, deleting the children as well.
ASSERT_TRUE(db().Execute("DELETE FROM parents"));
- EXPECT_TRUE(sql::test::CountTableRows(&db(), "children", &rows));
- EXPECT_EQ(0u, rows);
+ EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParents));
+ EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildren));
}
#if defined(MOJO_APPTEST_IMPL) || defined(OS_IOS)
@@ -453,4 +457,36 @@ TEST_F(SQLiteFeaturesTest, SmartAutoVacuum) {
}
#endif // !defined(USE_SYSTEM_SQLITE)
-} // namespace
+#if !defined(USE_SYSTEM_SQLITE)
+// 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) {
+ base::FilePath wal_path(db_path().value() + FILE_PATH_LITERAL("-wal"));
+
+ // Turn on WAL mode, then verify that the mode changed (WAL is supported).
+ ASSERT_TRUE(db().Execute("PRAGMA journal_mode = WAL"));
+ ASSERT_EQ("wal", ExecuteWithResult(&db(), "PRAGMA journal_mode"));
+
+ // The WAL file is created lazily on first change.
+ ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+
+ // By default, the WAL is checkpointed then deleted on close.
+ ASSERT_TRUE(GetPathExists(wal_path));
+ db().Close();
+ ASSERT_FALSE(GetPathExists(wal_path));
+
+ // Reopen and configure the database to not checkpoint WAL on close.
+ ASSERT_TRUE(Reopen());
+ ASSERT_TRUE(db().Execute("PRAGMA journal_mode = WAL"));
+ ASSERT_TRUE(db().Execute("ALTER TABLE foo ADD COLUMN c"));
+ ASSERT_EQ(
+ SQLITE_OK,
+ sqlite3_db_config(db().db_, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, NULL));
+ ASSERT_TRUE(GetPathExists(wal_path));
+ db().Close();
+ ASSERT_TRUE(GetPathExists(wal_path));
+}
+#endif
+
+} // namespace sql