summaryrefslogtreecommitdiffstats
path: root/sql/test
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-18 04:18:47 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-18 04:18:47 +0000
commita8848a7685d5f673b30bc1f5336e6f9eba44fc41 (patch)
treedc1888152353c034340059cb229810ba3f4aab54 /sql/test
parent2a4ee00d34865b2486e84eaf001c0e18358c901d (diff)
downloadchromium_src-a8848a7685d5f673b30bc1f5336e6f9eba44fc41.zip
chromium_src-a8848a7685d5f673b30bc1f5336e6f9eba44fc41.tar.gz
chromium_src-a8848a7685d5f673b30bc1f5336e6f9eba44fc41.tar.bz2
Revert 235595 "Revert 235492 "[sql] Recover Favicons v5 database..."
> Revert 235492 "[sql] Recover Favicons v5 databases, with more re..." > > Speculative revert to find the cause for Mac size regression > (will revert this revert later) > > > [sql] Recover Favicons v5 databases, with more recovery automation. > > > > An entirely automated recovery system runs afoul of questions about > > whether the corrupt database's schema can be trusted. > > sql::Recovery::AutoRecoverTable() uses a schema created by the caller > > to construct the recovery virtual table and then copies the data over. > > > > sql::Recovery::SetupMeta() and GetMetaVersionNumber() simplify > > accessing meta-table info in the corrupt database. > > > > sql::test::IntegrityCheck() and CorruptSizeInHeader() helpers to > > simplify common testing operations. > > > > Rewrite ThumbnailDatabase v6 and v7 recovery code and tests using > > these changes, and add a v5 recovery path. Additionally handle > > deprecated versions. > > > > BUG=240396,109482 > > > > Review URL: https://codereview.chromium.org/50493012 > > TBR=shess@chromium.org > > Review URL: https://codereview.chromium.org/74933002 TBR=kinuko@chromium.org Review URL: https://codereview.chromium.org/74953002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235604 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sql/test')
-rw-r--r--sql/test/test_helpers.cc71
-rw-r--r--sql/test/test_helpers.h17
2 files changed, 88 insertions, 0 deletions
diff --git a/sql/test/test_helpers.cc b/sql/test/test_helpers.cc
index de3e8f8..5438bd6 100644
--- a/sql/test/test_helpers.cc
+++ b/sql/test/test_helpers.cc
@@ -21,11 +21,73 @@ size_t CountSQLItemsOfType(sql::Connection* db, const char* type) {
return s.ColumnInt(0);
}
+// Helper for reading a number from the SQLite header.
+// See net/base/big_endian.h.
+unsigned ReadBigEndian(unsigned char* buf, size_t bytes) {
+ unsigned r = buf[0];
+ for (size_t i = 1; i < bytes; i++) {
+ r <<= 8;
+ r |= buf[i];
+ }
+ return r;
+}
+
+// Helper for writing a number to the SQLite header.
+void WriteBigEndian(unsigned val, unsigned char* buf, size_t bytes) {
+ for (size_t i = 0; i < bytes; i++) {
+ buf[bytes - i - 1] = (val & 0xFF);
+ val >>= 8;
+ }
+}
+
} // namespace
namespace sql {
namespace test {
+bool CorruptSizeInHeader(const base::FilePath& db_path) {
+ // See http://www.sqlite.org/fileformat.html#database_header
+ const size_t kHeaderSize = 100;
+ const size_t kPageSizeOffset = 16;
+ const size_t kFileChangeCountOffset = 24;
+ const size_t kPageCountOffset = 28;
+ const size_t kVersionValidForOffset = 92; // duplicate kFileChangeCountOffset
+
+ unsigned char header[kHeaderSize];
+
+ file_util::ScopedFILE file(file_util::OpenFile(db_path, "rb+"));
+ if (!file.get())
+ return false;
+
+ if (0 != fseek(file.get(), 0, SEEK_SET))
+ return false;
+ if (1u != fread(header, sizeof(header), 1, file.get()))
+ return false;
+
+ int64 db_size = 0;
+ if (!file_util::GetFileSize(db_path, &db_size))
+ return false;
+
+ const unsigned page_size = ReadBigEndian(header + kPageSizeOffset, 2);
+
+ // One larger than the expected size.
+ const unsigned page_count = (db_size + page_size) / page_size;
+ WriteBigEndian(page_count, header + kPageCountOffset, 4);
+
+ // Update change count so outstanding readers know the info changed.
+ // Both spots must match for the page count to be considered valid.
+ unsigned change_count = ReadBigEndian(header + kFileChangeCountOffset, 4);
+ WriteBigEndian(change_count + 1, header + kFileChangeCountOffset, 4);
+ WriteBigEndian(change_count + 1, header + kVersionValidForOffset, 4);
+
+ if (0 != fseek(file.get(), 0, SEEK_SET))
+ return false;
+ if (1u != fwrite(header, sizeof(header), 1, file.get()))
+ return false;
+
+ return true;
+}
+
size_t CountSQLTables(sql::Connection* db) {
return CountSQLItemsOfType(db, "table");
}
@@ -91,5 +153,14 @@ bool CreateDatabaseFromSQL(const base::FilePath& db_path,
return db.Execute(sql.c_str());
}
+std::string IntegrityCheck(sql::Connection* db) {
+ sql::Statement statement(db->GetUniqueStatement("PRAGMA integrity_check"));
+
+ // SQLite should always return a row of data.
+ EXPECT_TRUE(statement.Step());
+
+ return statement.ColumnString(0);
+}
+
} // namespace test
} // namespace sql
diff --git a/sql/test/test_helpers.h b/sql/test/test_helpers.h
index 330f59a..b9d5e9b 100644
--- a/sql/test/test_helpers.h
+++ b/sql/test/test_helpers.h
@@ -5,6 +5,8 @@
#ifndef SQL_TEST_TEST_HELPERS_H_
#define SQL_TEST_TEST_HELPERS_H_
+#include <string>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -21,6 +23,16 @@ class Connection;
namespace sql {
namespace test {
+// SQLite stores the database size in the header, and if the actual
+// OS-derived size is smaller, the database is considered corrupt.
+// [This case is actually a common form of corruption in the wild.]
+// This helper sets the in-header size to one page larger than the
+// actual file size. The resulting file will return SQLITE_CORRUPT
+// for most operations unless PRAGMA writable_schema is turned ON.
+//
+// Returns false if any error occurs accessing the file.
+bool CorruptSizeInHeader(const base::FilePath& db_path) WARN_UNUSED_RESULT;
+
// Return the number of tables in sqlite_master.
size_t CountSQLTables(sql::Connection* db) WARN_UNUSED_RESULT;
@@ -43,6 +55,11 @@ bool CountTableRows(sql::Connection* db, const char* table, size_t* count);
bool CreateDatabaseFromSQL(const base::FilePath& db_path,
const base::FilePath& sql_path) WARN_UNUSED_RESULT;
+// Return the results of running "PRAGMA integrity_check" on |db|.
+// TODO(shess): sql::Connection::IntegrityCheck() is basically the
+// same, but not as convenient for testing. Maybe combine.
+std::string IntegrityCheck(sql::Connection* db) WARN_UNUSED_RESULT;
+
} // namespace test
} // namespace sql