diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-09-03 13:32:17 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-01 14:31:55 +0200 |
commit | 21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (patch) | |
tree | 91be119f694044dfc1ff9fdc054459e925de9df0 /chromium/sql | |
parent | 03c549e0392f92c02536d3f86d5e1d8dfa3435ac (diff) | |
download | qtwebengine-chromium-21ba0c5d4bf8fba15dddd97cd693bad2358b77fd.tar.gz |
BASELINE: Update Chromium to 92.0.4515.166
Change-Id: I42a050486714e9e54fc271f2a8939223a02ae364
Diffstat (limited to 'chromium/sql')
-rw-r--r-- | chromium/sql/BUILD.gn | 2 | ||||
-rw-r--r-- | chromium/sql/DIR_METADATA | 4 | ||||
-rw-r--r-- | chromium/sql/README.md | 399 | ||||
-rw-r--r-- | chromium/sql/database.cc | 24 | ||||
-rw-r--r-- | chromium/sql/database.h | 6 | ||||
-rw-r--r-- | chromium/sql/database_unittest.cc | 910 | ||||
-rw-r--r-- | chromium/sql/initialization.cc | 2 | ||||
-rw-r--r-- | chromium/sql/meta_table_unittest.cc | 120 | ||||
-rw-r--r-- | chromium/sql/recover_module/module_unittest.cc | 443 | ||||
-rw-r--r-- | chromium/sql/recover_module/parsing.cc | 12 | ||||
-rw-r--r-- | chromium/sql/recover_module/record.cc | 4 | ||||
-rw-r--r-- | chromium/sql/recover_module/table.cc | 16 | ||||
-rw-r--r-- | chromium/sql/recover_module/table.h | 2 | ||||
-rw-r--r-- | chromium/sql/recovery_unittest.cc | 562 | ||||
-rw-r--r-- | chromium/sql/sandboxed_vfs.cc | 2 | ||||
-rw-r--r-- | chromium/sql/sandboxed_vfs.h | 4 | ||||
-rw-r--r-- | chromium/sql/sql_memory_dump_provider.h | 6 | ||||
-rw-r--r-- | chromium/sql/sql_memory_dump_provider_unittest.cc | 32 | ||||
-rw-r--r-- | chromium/sql/sqlite_features_unittest.cc | 172 | ||||
-rw-r--r-- | chromium/sql/statement.cc | 4 | ||||
-rw-r--r-- | chromium/sql/statement_unittest.cc | 53 | ||||
-rw-r--r-- | chromium/sql/transaction_unittest.cc | 68 |
22 files changed, 1720 insertions, 1127 deletions
diff --git a/chromium/sql/BUILD.gn b/chromium/sql/BUILD.gn index c7fd00f9950..e589f9a0994 100644 --- a/chromium/sql/BUILD.gn +++ b/chromium/sql/BUILD.gn @@ -121,8 +121,6 @@ test("sql_unittests") { "test/paths.cc", "test/paths.h", "test/run_all_unittests.cc", - "test/sql_test_base.cc", - "test/sql_test_base.h", "test/sql_test_suite.cc", "test/sql_test_suite.h", "transaction_unittest.cc", diff --git a/chromium/sql/DIR_METADATA b/chromium/sql/DIR_METADATA index 35767266bdf..0e619390a7a 100644 --- a/chromium/sql/DIR_METADATA +++ b/chromium/sql/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Storage" diff --git a/chromium/sql/README.md b/chromium/sql/README.md new file mode 100644 index 00000000000..3303502f8dd --- /dev/null +++ b/chromium/sql/README.md @@ -0,0 +1,399 @@ +# SQLite abstraction layer + + +## SQLite for system designers + +[SQLite](https://www.sqlite.org/) is a +[relational database management system (RDBMS)](https://en.wikipedia.org/wiki/Relational_database#RDBMS) +that [supports most of SQL](https://www.sqlite.org/lang.html). + +SQLite is architected as a library that can be embedded in another application, +such as Chrome. SQLite runs in the application's process, and shares its memory +and other resources. This is similar to embedded databases like +[LevelDB](https://github.com/google/leveldb) and +[BerkeleyDB](https://en.wikipedia.org/wiki/Berkeley_DB). By contrast, most +popular RDMBSes, like [PostgreSQL](https://www.postgresql.org/) and +[MySQL](https://www.mysql.com/), are structured as standalone server processes +that accept queries from client processes. + +TODO: Explain the process model and locking + +TODO: Explain Chrome decisions -- exclusive locking, full per-feature isolation +(separate databases and page caches) + + +## SQLite for database designers + +The section summarizes aspects of SQLite that are relevant to schema and +query design, and may be surprising to readers with prior experience in other +popular SQL database systems, such as +[PostgreSQL](https://www.postgresql.org/) and [MySQL](https://www.mysql.com/). + + +### Data types + +SQLite stores data using [5 major types](https://www.sqlite.org/datatype3.html), +which are summarized below. + +1. NULL is a special type for the `NULL` value. + +2. INTEGER represents big-endian twos-complement integers. Boolean values + (`TRUE` and `FALSE`) are represented as the integer values 1 and 0. + +3. REAL represents IEEE 754-2008 64-bit floating point numbers. + +4. TEXT represents strings (sequences of characters) encoded using a + [supported SQLite encoding](https://www.sqlite.org/c3ref/c_any.html). These + values are + [sorted](https://www.sqlite.org/datatype3.html#sort_order) according to + [a collating sequence](https://www.sqlite.org/datatype3.html#collation) or + [a collating function](https://www.sqlite.org/c3ref/create_collation.html). + +5. BLOB represents sequences of bytes that are opaque to SQLite. These values are + sorted using the bitwise binary comparison offered by + [memcmp](https://en.cppreference.com/w/cpp/string/byte/memcmp). + +SQLite stores index keys and row values (records / tuples) using +[a tightly packed format](https://sqlite.org/fileformat2.html#record_format) +that makes heavy use of [varints](https://sqlite.org/fileformat2.html#varint) +and variable-length fields. The column types have almost no influence on the +encoding of values. This has the following consequences. + +* All SQL integer types, such as `TINYINT` and `BIGINT`, are treated as aliases + for `INTEGER`. +* All SQL non-integer numeric types, such as `DECIMAL`, `FLOAT`, and + `DOUBLE PRECISION` are treated as aliases for `REAL`. +* Numeric precision and scale specifiers, such as `DECIMAL(5,2)` are ignored. +* All string types, such as `CHAR`, `CHARACTER VARYING`, `VARCHAR`, and `CLOB`, + are treated as aliases for `TEXT`. +* Maximum string length specifiers, such as `CHAR(255)` are ignored. + +SQLite uses clever heuristics, called +[type affinity](https://www.sqlite.org/datatype3.html#type_affinity), +to map SQL column types such as `VARCHAR` to the major types above. + +Chrome database schemas should avoid type affinity, and should not include any +information ignored by SQLite. + + +### Indexing + +SQLite [uses B-trees](https://www.sqlite.org/fileformat2.html#pages) to store +both table and index data. + +The exclusive use of B-trees reduces the amount of schema design decisions. +Notable examples: + +* There is no equivalent to + [PostgreSQL's index types](https://www.postgresql.org/docs/13/indexes-types.html). + In particular, since there are no hashed indexes, the design does not need to + consider whether the index only needs to support equality queries, as opposed + to greater/smaller than comparisons. + +* There is no equivalent to + [PostgreSQL's table access methods](https://www.postgresql.org/docs/13/tableam.html). + Each table is clustered by a primary key index, which is implicitly stored in + the table's B-tree. + +By default, table rows (records / tuples) are stored in a B-tree keyed by +[rowid](https://sqlite.org/lang_createtable.html#rowid), an automatically +assigned 64-bit integer key. Effectively, these tables are clustered by rowid, +which acts as an implicit primary key. Opting out of this SQLite-specific +default requires appending +[`WITHOUT ROWID`](https://sqlite.org/withoutrowid.html) to the `CREATE TABLE` +instruction. + +SQLite's [B-tree page format](https://sqlite.org/fileformat2.html#b_tree_pages) +has optimized special cases for tables clustered by rowid. This makes rowid the +most efficient [surrogate key](https://en.wikipedia.org/wiki/Surrogate_key) +implementation in SQLite. To make this optimization easier to use, any column +that is a primary key and has an `INTEGER` type is considered an alias for +rowid. + + +### Query processing + +[At a high level](https://www.sqlite.org/arch.html), SQLite compiles SQL queries +into bytecode executed by a virtual machine called the VDBE, or +[the bytecode engine](https://www.sqlite.org/opcode.html). A compiled query can +be executed multiple times, amortizing the costs of query parsing and planning. +Chrome's SQLite abstraction layer makes it easy to use compiled queries. + +The following SQLite documentation pages cover the query planner and +optimizer. + +1. [query planner overview](https://www.sqlite.org/queryplanner.html) +2. [query optimizer overview](https://www.sqlite.org/optoverview.html) +3. [`EXPLAIN QUERY PLAN` output description](https://www.sqlite.org/eqp.html) + +TODO: Present a simplified model that's sufficient for most database design. + + +## General advice + +The following pieces of advice usually come up in code reviews. + +### SQL style + +SQLite queries are usually embedded as string literals in C++ code. The +advice here has the following goals. + +1. Easy to read queries. The best defense against subtle bugs is making the + queries very easy to read, so that any bugs become obvious at code review + time. SQL string literals don't benefit from our code analysis + infrastructure, so the only lines of defense against bugs are testing and + code review. + +2. Simplify crash debugging. We will always have a low volume of non-actionable + crash reports, because Chrome runs on billions of devices, some of which have + faulty RAM or processors. + +3. No unnecessary performance overheads. The C++ optimizer doesn't understand + SQL query literals, so the queries end up as written in the Chrome binary. + Extra characters cost binary size, as well as CPU time (which turns into + battery usage) during query parsing. + +4. Match the embedding language (C++) style guide. This reduces the mental + context switch overhead for folks who write and/or review C++ code that + contains SQL. + +Format statements like so. + +```cc + static constexpr char kOriginInfoSql[] = + // clang-format off + "CREATE TABLE origin_infos(" + "origin TEXT NOT NULL," + "last_modified INTEGER NOT NULL," + "secure INTEGER NOT NULL)"; + // clang-format on + + static constexpr char kInsertSql[] = + // clang-format off + "INSERT INTO infos(origin,last_modified,secure) " + "VALUES (?,?,?)"; + // clang-format on + + static constexpr char kSelectSql[] = + // clang-format off + "SELECT origin,last_modified,secure FROM origins " + "WHERE last_modified > ? " + "ORDER BY last_modified"; + // clang-format on +``` + +* SQLite keywords should use ALL CAPS. This makes SQL query literals easier to + distinguish and search for. + +* Identifiers, such as table and row names, should use snake_case. + +* Identifiers, keywords, and parameter placeholders (`?`) should be separated by + exactly one character. Separators may be spaces (` `), commas (`,`), or + parentheses (`(`, `)`). + +* Statement-ending semicolons (`;`) are omitted. + +* SQL statements are stored in variables typed `static constexpr char[]`, or in + string literals passed directly to methods. + +* [`INSERT` statements](https://sqlite.org/lang_insert.html) should list all the + table columns by name, in the same order as the corresponding `CREATE TABLE` + statements. + +* [`SELECT` statements](https://sqlite.org/lang_select.html) should list the + desired table columns by name, in the same order as the corresponding + `CREATE TABLE` statements. `SELECT *` is strongly discouraged, at least until + we have schema checks on database opens. + +* [`SELECT` statements](https://sqlite.org/lang_select.html) that retrieve more + than one row should include an + [`ORDER BY` clause](https://sqlite.org/lang_select.html#the_order_by_clause) + to clarify the implicit ordering. + * SELECTs whose outer loop is a table search or table scan implicitly order + results by [rowid](https://sqlite.org/lang_createtable.html#rowid) or, in + the case of [`WITHOUT ROWID`](https://sqlite.org/withoutrowid.html) tables, + by the table's primary key. + * SELECTs whose outer loop is an index scan or index search order results + according to that index. + +* [`CREATE INDEX` statements](https://sqlite.org/lang_createindex.html) should + immediately follow the + [`CREATE TABLE` statement](https://sqlite.org/lang_createtable.html) for the + indexed table. + +* Explicit `CREATE UNIQUE INDEX` statements should be preferred to + [`UNIQUE` constraints on `CREATE TABLE`](https://sqlite.org/lang_createtable.html#unique_constraints). + +* Values must either be embedded in the SQL statement string literal, or bound + using [parameters](https://www.sqlite.org/lang_expr.html#varparam). + +* Parameter placeholders should always use the `?` syntax. Alternative syntaxes, + such as `?NNN` or `:AAAA`, have few benefits in a codebase where the `Bind` + statements are right next to the queries, and are less known to readers. + +* Do not execute multiple SQL statements (e.g., by calling `Step()` or `Run()` + on `sql::Statement`) on the same C++ line. It's difficult to get more than + line numbers from crash reports' stack traces. + + +### Schema style + +Column types should only be one of the the SQLite storage types (`INTEGER`, +`REAL`, `TEXT`, `BLOB`), so readers can avoid reasoning about SQLite's type +affinity. + +Columns that will store boolean values should have the `INTEGER` type. + +Columns that will store `base::Time` values should have the `INTEGER` type. +Values should be serialized using `sql::Statement::BindTime()` and deserialized +using `sql::Statement::ColumnTime()`. + +Column types should not include information ignored by SQLite, such as numeric +precision or scale specifiers, or string length specifiers. + +Columns should have the `NOT NULL` constraint whenever possible. This saves +maintainers from having to reason about the less intuitive cases of +[`NULL` handling](https://sqlite.org/nulls.html). + +Columns should avoid `DEFAULT` values. This moves the burden of checking that +`INSERT` statements aren't missing any columns from the code reviewer to SQLite. + +Surrogate primary keys should use the column type `INTEGER PRIMARY KEY`, to take +advantage of SQLite's rowid optimizations. +[`AUTOINCREMENT`](https://www.sqlite.org/autoinc.html) should only be used where +primary key reuse would be unacceptable. + + +### Discouraged features + +#### PRAGMA statements + +[`PRAGMA` statements](https://www.sqlite.org/pragma.html) should never be used +directly. Chrome's SQLite abstraction layer should be modified to support the +desired effects instead. + +Direct `PRAGMA` use limits our ability to customize and secure our SQLite build. +`PRAGMA` statements may turn on code paths with less testing / fuzzing coverage. +Furthermore, some `PRAGMA` statements invalidate previously compiled queries, +reducing the efficiency of Chrome's compiled query cache. + +#### Virtual tables + +[`CREATE VIRTUAL TABLE` statements](https://www.sqlite.org/vtab.html) should not +be used. The desired functionality should be implemented in C++, and access +storage using standard SQL statements. + +Virtual tables are [SQLite's module system](https://www.sqlite.org/vtab.html). +SQL statements on virtual tables are essentially running arbitrary code, which +makes them very difficult to reason about and maintain. Furthermore, the virtual +table implementations don't receive the same level of fuzzing coverage as the +SQLite core. + +Chrome's SQLite build has virtual table functionality reduced to the minimum +needed to support [FTS3](https://www.sqlite.org/fts3.html) in WebSQL, and an +internal feature. +[SQLite's run-time loading mechanism](https://www.sqlite.org/loadext.html) is +disabled, and most +[built-in virtual tables](https://www.sqlite.org/vtablist.html) are disabled as +well. + +After +[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan +to disable SQLite's virtual table support using +[SQLITE_OMIT_VIRTUALTABLE](https://sqlite.org/compile.html#omit_virtualtable). + +#### Foreign key constraints + +[SQL foreign key constraints](https://sqlite.org/foreignkeys.html) should not be +used. All data validation should be performed using explicit `SELECT` statements +(generally wrapped as helper methods) inside transactions. Cascading deletions +should be performed using explicit `DELETE` statements inside transactions. + +Chrome features cannot rely on foreign key enforcement, due to the +possibility of data corruption. Furthermore, foreign key constraints make it +more difficult to reason about system behavior (Chrome feature code + SQLite) +when the database gets corrupted. Foreign key constraints also make it more +difficult to reason about query performance. + +After +[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan +to disable SQLite's foreign key support using +[SQLITE_OMIT_FOREIGN_KEY](https://sqlite.org/compile.html#omit_foreign_key). + +#### CHECK constraints + +[SQL CHECK constraints](https://sqlite.org/lang_createtable.html#check_constraints) +should not be used, for the same reasons as foreign key constraints. The +equivalent checks should be performed in C++, typically using `DCHECK`. + +After +[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan +to disable SQLite's CHECK constraint support using +[SQLITE_OMIT_CHECK](https://sqlite.org/compile.html#omit_check). + +#### Triggers + +[SQL triggers](https://sqlite.org/lang_createtrigger.html) should not be used. + +Triggers significantly increase the difficulty of reviewing and maintaining +Chrome features that use them. + +After [WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we +plan to disable SQLite's trigger support using +[SQLITE_OMIT_TRIGGER](https://sqlite.org/compile.html#omit_trigger). + +#### Common Table Expressions + +[SQL Common Table Expressions (CTEs)](https://sqlite.org/lang_with.html) should +not be used. Chrome's SQL schemas and queries should be simple enough that +the factoring afforded by +[ordinary CTEs](https://sqlite.org/lang_with.html#ordinary_common_table_expressions) +is not necessary. +[Recursive CTEs](https://sqlite.org/lang_with.html#recursive_common_table_expressions) +should be implemented in C++. + +Common Table Expressions do not open up any query optimizations that would not +be available otherwise, and make it more difficult to review / analyze queries. + +#### Views + +SQL views, managed by the +[`CREATE VIEW` statement](https://www.sqlite.org/lang_createview.html) and the +[`DROP VIEW` statement](https://www.sqlite.org/lang_dropview.html), should not +be used. Chrome's SQL schemas and queries should be simple enough that the +factoring afforded by views is not necessary. + +Views are syntactic sugar, and do not open up any new SQL capabilities. SQL +statements on views are more difficult to understand and maintain, because of +the extra layer of indirection. + +After +[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan +to disable SQLite's VIEW support using +[SQLITE_OMIT_VIEW](https://www.sqlite.org/compile.html#omit_view). + +#### Compound SELECT statements + +[Compound SELECT statements](https://www.sqlite.org/lang_select.html#compound_select_statements) +should not be used. Such statements should be broken down into +[simple SELECT statements](https://www.sqlite.org/lang_select.html#simple_select_processing), +and the operators `UNION`, `UNION ALL`, `INTERSECT` and `EXCEPT` should be +implemented in C++. + +A single compound SELECT statement is more difficult to review and properly +unit-test than the equivalent collection of simple SELECT statements. +Furthermore, the compound SELECT statement operators can be implemented more efficiently in C++ than in SQLite's bytecode interpreter (VDBE). + +After +[WebSQL](https://www.w3.org/TR/webdatabase/) is removed from Chrome, we plan +to disable SQLite's compound SELECT support using +[SQLITE_OMIT_COMPOUND_SELECT](https://www.sqlite.org/compile.html#omit_compound_select). + +#### ATTACH DATABASE statements + +[`ATTACH DATABASE` statements](https://www.sqlite.org/lang_attach.html) should +not be used. Each Chrome feature should store its data in a single database. +Chrome code should not assume that transactions across multiple databases are +atomic. + +We plan to remove all existing `ATTACH DATABASE` use from Chrome. diff --git a/chromium/sql/database.cc b/chromium/sql/database.cc index 73fff33cd6e..46ce567cfe6 100644 --- a/chromium/sql/database.cc +++ b/chromium/sql/database.cc @@ -222,7 +222,7 @@ void Database::StatementRef::Close(bool forced) { // allowing disk access. // TODO(paivanof@gmail.com): This should move to the beginning // of the function. http://crbug.com/136655. - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); sqlite3_finalize(stmt_); stmt_ = nullptr; @@ -315,7 +315,7 @@ void Database::CloseInternal(bool forced) { // will happen on thread not allowing disk access. // TODO(paivanof@gmail.com): This should move to the beginning // of the function. http://crbug.com/136655. - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); // Resetting acquires a lock to ensure no dump is happening on the database @@ -359,7 +359,7 @@ void Database::Preload() { return; } - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); // Maximum number of bytes that will be prefetched from the database. @@ -649,7 +649,7 @@ bool Database::SetMmapAltStatus(int64_t status) { size_t Database::GetAppropriateMmapSize() { TRACE_EVENT0("sql", "Database::GetAppropriateMmapSize"); - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); // How much to map if no errors are found. 50MB encompasses the 99th @@ -794,7 +794,7 @@ void Database::TrimMemory() { bool Database::Raze() { TRACE_EVENT0("sql", "Database::Raze"); - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); if (!db_) { @@ -1147,7 +1147,7 @@ int Database::ExecuteAndReturnErrorCode(const char* sql) { return SQLITE_ERROR; } - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); int rc = SQLITE_OK; @@ -1270,7 +1270,7 @@ scoped_refptr<Database::StatementRef> Database::GetStatementImpl( if (!db_) return base::MakeRefCounted<StatementRef>(nullptr, nullptr, poisoned_); - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); // TODO(pwnall): Cached statements (but not unique statements) should be @@ -1319,7 +1319,7 @@ std::string Database::GetSchema() const { } bool Database::IsSQLValid(const char* sql) { - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); if (!db_) { DCHECK(poisoned_) << "Illegal use of Database without a db"; @@ -1383,7 +1383,9 @@ int64_t Database::GetLastInsertRowId() const { DCHECK(poisoned_) << "Illegal use of Database without a db"; return 0; } - return sqlite3_last_insert_rowid(db_); + int64_t last_rowid = sqlite3_last_insert_rowid(db_); + DCHECK(last_rowid != 0) << "No successful INSERT in a table with ROWID"; + return last_rowid; } int Database::GetLastChangeCount() const { @@ -1453,7 +1455,7 @@ bool Database::OpenInternal(const std::string& file_name, return false; } - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); EnsureSqliteInitialized(); @@ -1822,7 +1824,7 @@ bool Database::UseWALMode() const { } bool Database::CheckpointDatabase() { - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); static const char* kMainDb = "main"; diff --git a/chromium/sql/database.h b/chromium/sql/database.h index 35601a48e1d..93906e65b32 100644 --- a/chromium/sql/database.h +++ b/chromium/sql/database.h @@ -21,12 +21,12 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/threading/scoped_blocking_call.h" #include "sql/internal_api_token.h" #include "sql/sql_features.h" #include "sql/statement_id.h" +#include "third_party/abseil-cpp/absl/types/optional.h" struct sqlite3; struct sqlite3_stmt; @@ -580,7 +580,7 @@ class COMPONENT_EXPORT(SQL) Database { // declare its blocking execution scope (see https://www.crbug/934302). void InitScopedBlockingCall( const base::Location& from_here, - base::Optional<base::ScopedBlockingCall>* scoped_blocking_call) const { + absl::optional<base::ScopedBlockingCall>* scoped_blocking_call) const { if (!in_memory_) scoped_blocking_call->emplace(from_here, base::BlockingType::MAY_BLOCK); } @@ -650,7 +650,7 @@ class COMPONENT_EXPORT(SQL) Database { // declare its blocking execution scope (see https://www.crbug/934302). void InitScopedBlockingCall( const base::Location& from_here, - base::Optional<base::ScopedBlockingCall>* scoped_blocking_call) const { + absl::optional<base::ScopedBlockingCall>* scoped_blocking_call) const { if (database_) database_->InitScopedBlockingCall(from_here, scoped_blocking_call); } diff --git a/chromium/sql/database_unittest.cc b/chromium/sql/database_unittest.cc index 9ae6a176e67..c2d65167d96 100644 --- a/chromium/sql/database_unittest.cc +++ b/chromium/sql/database_unittest.cc @@ -2,21 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "sql/database.h" + #include <stddef.h> #include <stdint.h> #include "base/bind.h" #include "base/files/file_util.h" -#include "base/files/scoped_file.h" #include "base/files/scoped_temp_dir.h" #include "base/logging.h" -#include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/test/gtest_util.h" #include "base/test/metrics/histogram_tester.h" #include "base/trace_event/process_memory_dump.h" #include "build/build_config.h" -#include "sql/database.h" #include "sql/database_memory_dump_provider.h" #include "sql/meta_table.h" #include "sql/sql_features.h" @@ -24,7 +23,6 @@ #include "sql/test/database_test_peer.h" #include "sql/test/error_callback_support.h" #include "sql/test/scoped_error_expecter.h" -#include "sql/test/sql_test_base.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" @@ -37,9 +35,9 @@ using sql::test::ExecuteWithResult; // Helper to return the count of items in sqlite_master. Return -1 in // case of error. -int SqliteMasterCount(sql::Database* db) { +int SqliteMasterCount(Database* db) { const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master"; - sql::Statement s(db->GetUniqueStatement(kMasterCount)); + Statement s(db->GetUniqueStatement(kMasterCount)); return s.Step() ? s.ColumnInt(0) : -1; } @@ -48,7 +46,7 @@ int SqliteMasterCount(sql::Database* db) { // explicitly having the ref count live longer than the object. class RefCounter { public: - RefCounter(size_t* counter) : counter_(counter) { (*counter_)++; } + explicit RefCounter(size_t* counter) : counter_(counter) { (*counter_)++; } RefCounter(const RefCounter& other) : counter_(other.counter_) { (*counter_)++; } @@ -61,24 +59,24 @@ class RefCounter { }; // Empty callback for implementation of ErrorCallbackSetHelper(). -void IgnoreErrorCallback(int error, sql::Statement* stmt) {} +void IgnoreErrorCallback(int error, Statement* stmt) {} -void ErrorCallbackSetHelper(sql::Database* db, +void ErrorCallbackSetHelper(Database* db, size_t* counter, const RefCounter& r, int error, - sql::Statement* stmt) { + Statement* stmt) { // The ref count should not go to zero when changing the callback. EXPECT_GT(*counter, 0u); db->set_error_callback(base::BindRepeating(&IgnoreErrorCallback)); EXPECT_GT(*counter, 0u); } -void ErrorCallbackResetHelper(sql::Database* db, +void ErrorCallbackResetHelper(Database* db, size_t* counter, const RefCounter& r, int error, - sql::Statement* stmt) { + Statement* stmt) { // The ref count should not go to zero when clearing the callback. EXPECT_GT(*counter, 0u); db->reset_error_callback(); @@ -86,10 +84,10 @@ void ErrorCallbackResetHelper(sql::Database* db, } // Handle errors by blowing away the database. -void RazeErrorCallback(sql::Database* db, +void RazeErrorCallback(Database* db, int expected_error, int error, - sql::Statement* stmt) { + Statement* stmt) { // Nothing here needs extended errors at this time. EXPECT_EQ(expected_error, expected_error & 0xff); EXPECT_EQ(expected_error, error & 0xff); @@ -106,23 +104,36 @@ class ScopedUmaskSetter { } ~ScopedUmaskSetter() { umask(old_umask_); } + ScopedUmaskSetter(const ScopedUmaskSetter&) = delete; + ScopedUmaskSetter& operator=(const ScopedUmaskSetter&) = delete; + private: mode_t old_umask_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); }; #endif // defined(OS_POSIX) } // namespace // We use the parameter to run all tests with WAL mode on and off. -class SQLDatabaseTest : public SQLTestBase, +class SQLDatabaseTest : public testing::Test, public testing::WithParamInterface<bool> { public: - SQLDatabaseTest() : SQLTestBase(GetDBOptions()) {} - explicit SQLDatabaseTest(DatabaseOptions options) : SQLTestBase(options) {} + enum class OverwriteType { + kTruncate, + kOverwrite, + }; + + ~SQLDatabaseTest() override = default; + + void SetUp() override { + db_ = std::make_unique<Database>(GetDBOptions()); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_path_ = temp_dir_.GetPath().AppendASCII("database_test.sqlite"); + ASSERT_TRUE(db_->Open(db_path_)); + } - sql::DatabaseOptions GetDBOptions() { - sql::DatabaseOptions options; + DatabaseOptions GetDBOptions() { + DatabaseOptions options; options.wal_mode = IsWALEnabled(); // TODO(crbug.com/1120969): Remove after switching to exclusive mode on by // default. @@ -135,186 +146,211 @@ class SQLDatabaseTest : public SQLTestBase, #endif // defined(OS_FUCHSIA) return options; } + bool IsWALEnabled() { return GetParam(); } + + bool TruncateDatabase() { + base::File file(db_path_, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + return file.SetLength(0); + } + + bool OverwriteDatabaseHeader(OverwriteType type) { + base::File file(db_path_, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + if (type == OverwriteType::kTruncate) { + if (!file.SetLength(0)) + return false; + } + + static constexpr char kText[] = "Now is the winter of our discontent."; + constexpr int kTextBytes = sizeof(kText) - 1; + return file.Write(0, kText, kTextBytes) == kTextBytes; + } + + protected: + base::ScopedTempDir temp_dir_; + base::FilePath db_path_; + std::unique_ptr<Database> db_; }; TEST_P(SQLDatabaseTest, Execute) { // Valid statement should return true. - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - EXPECT_EQ(SQLITE_OK, db().GetErrorCode()); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + EXPECT_EQ(SQLITE_OK, db_->GetErrorCode()); // Invalid statement should fail. ASSERT_EQ(SQLITE_ERROR, - db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b")); - EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode()); + db_->ExecuteAndReturnErrorCode("CREATE TAB foo (a, b")); + EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode()); } TEST_P(SQLDatabaseTest, ExecuteWithErrorCode) { ASSERT_EQ(SQLITE_OK, - db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)")); - ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE")); - ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode( + db_->ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)")); + ASSERT_EQ(SQLITE_ERROR, db_->ExecuteAndReturnErrorCode("CREATE TABLE TABLE")); + ASSERT_EQ(SQLITE_ERROR, db_->ExecuteAndReturnErrorCode( "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)")); } TEST_P(SQLDatabaseTest, CachedStatement) { - sql::StatementID id1 = SQL_FROM_HERE; - sql::StatementID id2 = SQL_FROM_HERE; + StatementID id1 = SQL_FROM_HERE; + StatementID id2 = SQL_FROM_HERE; static const char kId1Sql[] = "SELECT a FROM foo"; static const char kId2Sql[] = "SELECT b FROM foo"; - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)")); sqlite3_stmt* raw_id1_statement; sqlite3_stmt* raw_id2_statement; { - scoped_refptr<sql::Database::StatementRef> ref_from_id1 = - db().GetCachedStatement(id1, kId1Sql); + scoped_refptr<Database::StatementRef> ref_from_id1 = + db_->GetCachedStatement(id1, kId1Sql); raw_id1_statement = ref_from_id1->stmt(); - sql::Statement from_id1(std::move(ref_from_id1)); + Statement from_id1(std::move(ref_from_id1)); ASSERT_TRUE(from_id1.is_valid()); ASSERT_TRUE(from_id1.Step()); EXPECT_EQ(12, from_id1.ColumnInt(0)); - scoped_refptr<sql::Database::StatementRef> ref_from_id2 = - db().GetCachedStatement(id2, kId2Sql); + scoped_refptr<Database::StatementRef> ref_from_id2 = + db_->GetCachedStatement(id2, kId2Sql); raw_id2_statement = ref_from_id2->stmt(); EXPECT_NE(raw_id1_statement, raw_id2_statement); - sql::Statement from_id2(std::move(ref_from_id2)); + Statement from_id2(std::move(ref_from_id2)); ASSERT_TRUE(from_id2.is_valid()); ASSERT_TRUE(from_id2.Step()); EXPECT_EQ(13, from_id2.ColumnInt(0)); } { - scoped_refptr<sql::Database::StatementRef> ref_from_id1 = - db().GetCachedStatement(id1, kId1Sql); + scoped_refptr<Database::StatementRef> ref_from_id1 = + db_->GetCachedStatement(id1, kId1Sql); EXPECT_EQ(raw_id1_statement, ref_from_id1->stmt()) << "statement was not cached"; - sql::Statement from_id1(std::move(ref_from_id1)); + Statement from_id1(std::move(ref_from_id1)); ASSERT_TRUE(from_id1.is_valid()); ASSERT_TRUE(from_id1.Step()) << "cached statement was not reset"; EXPECT_EQ(12, from_id1.ColumnInt(0)); - scoped_refptr<sql::Database::StatementRef> ref_from_id2 = - db().GetCachedStatement(id2, kId2Sql); + scoped_refptr<Database::StatementRef> ref_from_id2 = + db_->GetCachedStatement(id2, kId2Sql); EXPECT_EQ(raw_id2_statement, ref_from_id2->stmt()) << "statement was not cached"; - sql::Statement from_id2(std::move(ref_from_id2)); + Statement from_id2(std::move(ref_from_id2)); ASSERT_TRUE(from_id2.is_valid()); ASSERT_TRUE(from_id2.Step()) << "cached statement was not reset"; EXPECT_EQ(13, from_id2.ColumnInt(0)); } - EXPECT_DCHECK_DEATH(db().GetCachedStatement(id1, kId2Sql)) + EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id1, kId2Sql)) << "Using a different SQL with the same statement ID should DCHECK"; - EXPECT_DCHECK_DEATH(db().GetCachedStatement(id2, kId1Sql)) + EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id2, kId1Sql)) << "Using a different SQL with the same statement ID should DCHECK"; } TEST_P(SQLDatabaseTest, IsSQLValidTest) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo")); - ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->IsSQLValid("SELECT a FROM foo")); + ASSERT_FALSE(db_->IsSQLValid("SELECT no_exist FROM foo")); } TEST_P(SQLDatabaseTest, DoesTableExist) { - EXPECT_FALSE(db().DoesTableExist("foo")); - EXPECT_FALSE(db().DoesTableExist("foo_index")); + EXPECT_FALSE(db_->DoesTableExist("foo")); + EXPECT_FALSE(db_->DoesTableExist("foo_index")); - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().Execute("CREATE INDEX foo_index ON foo (a)")); - EXPECT_TRUE(db().DoesTableExist("foo")); - EXPECT_FALSE(db().DoesTableExist("foo_index")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)")); + EXPECT_TRUE(db_->DoesTableExist("foo")); + EXPECT_FALSE(db_->DoesTableExist("foo_index")); // DoesTableExist() is case-sensitive. - EXPECT_FALSE(db().DoesTableExist("Foo")); - EXPECT_FALSE(db().DoesTableExist("FOO")); + EXPECT_FALSE(db_->DoesTableExist("Foo")); + EXPECT_FALSE(db_->DoesTableExist("FOO")); } TEST_P(SQLDatabaseTest, DoesIndexExist) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - EXPECT_FALSE(db().DoesIndexExist("foo")); - EXPECT_FALSE(db().DoesIndexExist("foo_ubdex")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + EXPECT_FALSE(db_->DoesIndexExist("foo")); + EXPECT_FALSE(db_->DoesIndexExist("foo_ubdex")); - ASSERT_TRUE(db().Execute("CREATE INDEX foo_index ON foo (a)")); - EXPECT_TRUE(db().DoesIndexExist("foo_index")); - EXPECT_FALSE(db().DoesIndexExist("foo")); + ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)")); + EXPECT_TRUE(db_->DoesIndexExist("foo_index")); + EXPECT_FALSE(db_->DoesIndexExist("foo")); // DoesIndexExist() is case-sensitive. - EXPECT_FALSE(db().DoesIndexExist("Foo_index")); - EXPECT_FALSE(db().DoesIndexExist("Foo_Index")); - EXPECT_FALSE(db().DoesIndexExist("FOO_INDEX")); + EXPECT_FALSE(db_->DoesIndexExist("Foo_index")); + EXPECT_FALSE(db_->DoesIndexExist("Foo_Index")); + EXPECT_FALSE(db_->DoesIndexExist("FOO_INDEX")); } TEST_P(SQLDatabaseTest, DoesViewExist) { - EXPECT_FALSE(db().DoesViewExist("voo")); - ASSERT_TRUE(db().Execute("CREATE VIEW voo (a) AS SELECT 1")); - EXPECT_FALSE(db().DoesIndexExist("voo")); - EXPECT_FALSE(db().DoesTableExist("voo")); - EXPECT_TRUE(db().DoesViewExist("voo")); + EXPECT_FALSE(db_->DoesViewExist("voo")); + ASSERT_TRUE(db_->Execute("CREATE VIEW voo (a) AS SELECT 1")); + EXPECT_FALSE(db_->DoesIndexExist("voo")); + EXPECT_FALSE(db_->DoesTableExist("voo")); + EXPECT_TRUE(db_->DoesViewExist("voo")); // DoesTableExist() is case-sensitive. - EXPECT_FALSE(db().DoesViewExist("Voo")); - EXPECT_FALSE(db().DoesViewExist("VOO")); + EXPECT_FALSE(db_->DoesViewExist("Voo")); + EXPECT_FALSE(db_->DoesViewExist("VOO")); } TEST_P(SQLDatabaseTest, DoesColumnExist) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); - EXPECT_FALSE(db().DoesColumnExist("foo", "bar")); - EXPECT_TRUE(db().DoesColumnExist("foo", "a")); + EXPECT_FALSE(db_->DoesColumnExist("foo", "bar")); + EXPECT_TRUE(db_->DoesColumnExist("foo", "a")); - ASSERT_FALSE(db().DoesTableExist("bar")); - EXPECT_FALSE(db().DoesColumnExist("bar", "b")); + ASSERT_FALSE(db_->DoesTableExist("bar")); + EXPECT_FALSE(db_->DoesColumnExist("bar", "b")); // SQLite resolves table/column names without case sensitivity. - EXPECT_TRUE(db().DoesColumnExist("FOO", "A")); - EXPECT_TRUE(db().DoesColumnExist("FOO", "a")); - EXPECT_TRUE(db().DoesColumnExist("foo", "A")); + EXPECT_TRUE(db_->DoesColumnExist("FOO", "A")); + EXPECT_TRUE(db_->DoesColumnExist("FOO", "a")); + EXPECT_TRUE(db_->DoesColumnExist("foo", "A")); } TEST_P(SQLDatabaseTest, GetLastInsertRowId) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)")); + ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)")); // Last insert row ID should be valid. - int64_t row = db().GetLastInsertRowId(); + int64_t row = db_->GetLastInsertRowId(); EXPECT_LT(0, row); // It should be the primary key of the row we just inserted. - sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?")); + Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?")); s.BindInt64(0, row); ASSERT_TRUE(s.Step()); EXPECT_EQ(12, s.ColumnInt(0)); } TEST_P(SQLDatabaseTest, Rollback) { - ASSERT_TRUE(db().BeginTransaction()); - ASSERT_TRUE(db().BeginTransaction()); - EXPECT_EQ(2, db().transaction_nesting()); - db().RollbackTransaction(); - EXPECT_FALSE(db().CommitTransaction()); - EXPECT_TRUE(db().BeginTransaction()); + ASSERT_TRUE(db_->BeginTransaction()); + ASSERT_TRUE(db_->BeginTransaction()); + EXPECT_EQ(2, db_->transaction_nesting()); + db_->RollbackTransaction(); + EXPECT_FALSE(db_->CommitTransaction()); + EXPECT_TRUE(db_->BeginTransaction()); } // Test the scoped error expecter by attempting to insert a duplicate // value into an index. TEST_P(SQLDatabaseTest, ScopedErrorExpecter) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CONSTRAINT); - ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + ASSERT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); ASSERT_TRUE(expecter.SawExpectedErrors()); } } @@ -323,36 +359,36 @@ TEST_P(SQLDatabaseTest, ScopedErrorExpecter) { // with ScopedErrorExpecter. TEST_P(SQLDatabaseTest, ScopedIgnoreUntracked) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_FALSE(db().DoesTableExist("bar")); - ASSERT_TRUE(db().DoesTableExist("foo")); - ASSERT_TRUE(db().DoesColumnExist("foo", "id")); - db().Close(); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_FALSE(db_->DoesTableExist("bar")); + ASSERT_TRUE(db_->DoesTableExist("foo")); + ASSERT_TRUE(db_->DoesColumnExist("foo", "id")); + db_->Close(); // Corrupt the database so that nothing works, including PRAGMAs. - ASSERT_TRUE(CorruptSizeInHeaderOfDB()); + ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_)); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db().Open(db_path())); - ASSERT_FALSE(db().DoesTableExist("bar")); - ASSERT_FALSE(db().DoesTableExist("foo")); - ASSERT_FALSE(db().DoesColumnExist("foo", "id")); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_FALSE(db_->DoesTableExist("bar")); + ASSERT_FALSE(db_->DoesTableExist("foo")); + ASSERT_FALSE(db_->DoesColumnExist("foo", "id")); ASSERT_TRUE(expecter.SawExpectedErrors()); } } TEST_P(SQLDatabaseTest, ErrorCallback) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); int error = SQLITE_OK; { - sql::ScopedErrorCallback sec( - &db(), base::BindRepeating(&sql::CaptureErrorCallback, &error)); - EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + ScopedErrorCallback sec(db_.get(), + base::BindRepeating(&CaptureErrorCallback, &error)); + EXPECT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); // Later versions of SQLite throw SQLITE_CONSTRAINT_UNIQUE. The specific // sub-error isn't really important. @@ -364,7 +400,7 @@ TEST_P(SQLDatabaseTest, ErrorCallback) { error = SQLITE_OK; sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CONSTRAINT); - ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + ASSERT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); ASSERT_TRUE(expecter.SawExpectedErrors()); EXPECT_EQ(SQLITE_OK, error); } @@ -380,34 +416,34 @@ TEST_P(SQLDatabaseTest, ErrorCallback) { // live. { size_t count = 0; - sql::ScopedErrorCallback sec( - &db(), base::BindRepeating(&ErrorCallbackSetHelper, &db(), &count, - RefCounter(&count))); + ScopedErrorCallback sec( + db_.get(), base::BindRepeating(&ErrorCallbackSetHelper, db_.get(), + &count, RefCounter(&count))); - EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + EXPECT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); } // Same test, but reset_error_callback() case. { size_t count = 0; - sql::ScopedErrorCallback sec( - &db(), base::BindRepeating(&ErrorCallbackResetHelper, &db(), &count, - RefCounter(&count))); + ScopedErrorCallback sec( + db_.get(), base::BindRepeating(&ErrorCallbackResetHelper, db_.get(), + &count, RefCounter(&count))); - EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)")); + EXPECT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)")); } } -// Test that sql::Database::Raze() results in a database without the +// Test that Database::Raze() results in a database without the // tables from the original database. TEST_P(SQLDatabaseTest, Raze) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)")); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)")); int pragma_auto_vacuum = 0; { - sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum")); + Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum")); ASSERT_TRUE(s.Step()); pragma_auto_vacuum = s.ColumnInt(0); ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1); @@ -417,13 +453,13 @@ TEST_P(SQLDatabaseTest, Raze) { const int kExpectedPageCount = 2 + pragma_auto_vacuum; { - sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); + Statement s(db_->GetUniqueStatement("PRAGMA page_count")); ASSERT_TRUE(s.Step()); EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0)); } { - sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); + Statement s(db_->GetUniqueStatement("SELECT * FROM sqlite_master")); ASSERT_TRUE(s.Step()); EXPECT_EQ("table", s.ColumnString(0)); EXPECT_EQ("foo", s.ColumnString(1)); @@ -433,18 +469,18 @@ TEST_P(SQLDatabaseTest, Raze) { EXPECT_EQ(kCreateSql, s.ColumnString(4)); } - ASSERT_TRUE(db().Raze()); + ASSERT_TRUE(db_->Raze()); { - sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); + Statement s(db_->GetUniqueStatement("PRAGMA page_count")); ASSERT_TRUE(s.Step()); EXPECT_EQ(1, s.ColumnInt(0)); } - ASSERT_EQ(0, SqliteMasterCount(&db())); + ASSERT_EQ(0, SqliteMasterCount(db_.get())); { - sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum")); + Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum")); ASSERT_TRUE(s.Step()); // The new database has the same auto_vacuum as a fresh database. EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0)); @@ -466,8 +502,8 @@ void TestPageSize(const base::FilePath& db_prefix, const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII( base::NumberToString(initial_page_size)); - sql::Database::Delete(db_path); - sql::Database db({.page_size = initial_page_size}); + Database::Delete(db_path); + Database db({.page_size = initial_page_size}); ASSERT_TRUE(db.Open(db_path)); ASSERT_TRUE(db.Execute(kCreateSql)); ASSERT_TRUE(db.Execute(kInsertSql1)); @@ -477,7 +513,7 @@ void TestPageSize(const base::FilePath& db_prefix, db.Close(); // Re-open the database while setting a new |options.page_size| in the object. - sql::Database razed_db({.page_size = final_page_size}); + Database razed_db({.page_size = final_page_size}); ASSERT_TRUE(razed_db.Open(db_path)); // Raze will use the page size set in the connection object, which may not // match the file's page size. @@ -495,29 +531,29 @@ void TestPageSize(const base::FilePath& db_prefix, EXPECT_EQ("1", ExecuteWithResult(&razed_db, "PRAGMA page_count")); } -// Verify that sql::Recovery maintains the page size, and the virtual table +// Verify that Recovery maintains the page size, and the virtual table // works with page sizes other than SQLite's default. Also verify the case // where the default page size has changed. TEST_P(SQLDatabaseTest, RazePageSize) { const std::string default_page_size = - ExecuteWithResult(&db(), "PRAGMA page_size"); + ExecuteWithResult(db_.get(), "PRAGMA page_size"); // Sync uses 32k pages. EXPECT_NO_FATAL_FAILURE( - TestPageSize(db_path(), 32768, "32768", 32768, "32768")); + TestPageSize(db_path_, 32768, "32768", 32768, "32768")); // Many clients use 4k pages. This is the SQLite default after 3.12.0. - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 4096, "4096", 4096, "4096")); + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 4096, "4096", 4096, "4096")); // 1k is the default page size before 3.12.0. - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 1024, "1024", 1024, "1024")); + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 1024, "1024", 1024, "1024")); - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 2048, "2048", 4096, "4096")); + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048", 4096, "4096")); // Databases with no page size specified should result in the default // page size. 2k has never been the default page size. ASSERT_NE("2048", default_page_size); - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 2048, "2048", + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048", DatabaseOptions::kDefaultPageSize, default_page_size)); } @@ -525,15 +561,15 @@ TEST_P(SQLDatabaseTest, RazePageSize) { // Test that Raze() results are seen in other connections. TEST_P(SQLDatabaseTest, RazeMultiple) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kCreateSql)); - sql::Database other_db(GetDBOptions()); - ASSERT_TRUE(other_db.Open(db_path())); + Database other_db(GetDBOptions()); + ASSERT_TRUE(other_db.Open(db_path_)); // Check that the second connection sees the table. ASSERT_EQ(1, SqliteMasterCount(&other_db)); - ASSERT_TRUE(db().Raze()); + ASSERT_TRUE(db_->Raze()); // The second connection sees the updated database. ASSERT_EQ(0, SqliteMasterCount(&other_db)); @@ -541,26 +577,26 @@ TEST_P(SQLDatabaseTest, RazeMultiple) { TEST_P(SQLDatabaseTest, RazeLocked) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kCreateSql)); // Open a transaction and write some data in a second connection. // This will acquire a PENDING or EXCLUSIVE transaction, which will // cause the raze to fail. - sql::Database other_db(GetDBOptions()); - ASSERT_TRUE(other_db.Open(db_path())); + Database other_db(GetDBOptions()); + ASSERT_TRUE(other_db.Open(db_path_)); ASSERT_TRUE(other_db.BeginTransaction()); const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')"; ASSERT_TRUE(other_db.Execute(kInsertSql)); - ASSERT_FALSE(db().Raze()); + ASSERT_FALSE(db_->Raze()); // Works after COMMIT. ASSERT_TRUE(other_db.CommitTransaction()); - ASSERT_TRUE(db().Raze()); + ASSERT_TRUE(db_->Raze()); // Re-create the database. - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kInsertSql)); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kInsertSql)); // An unfinished read transaction in the other connection also // blocks raze. @@ -568,13 +604,13 @@ TEST_P(SQLDatabaseTest, RazeLocked) { // write operations when using a WAL. if (!IsWALEnabled()) { const char* kQuery = "SELECT COUNT(*) FROM foo"; - sql::Statement s(other_db.GetUniqueStatement(kQuery)); + Statement s(other_db.GetUniqueStatement(kQuery)); ASSERT_TRUE(s.Step()); - ASSERT_FALSE(db().Raze()); + ASSERT_FALSE(db_->Raze()); // Completing the statement unlocks the database. ASSERT_FALSE(s.Step()); - ASSERT_TRUE(db().Raze()); + ASSERT_TRUE(db_->Raze()); } } @@ -582,26 +618,26 @@ TEST_P(SQLDatabaseTest, RazeLocked) { // this as an empty database. TEST_P(SQLDatabaseTest, RazeEmptyDB) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - db().Close(); + ASSERT_TRUE(db_->Execute(kCreateSql)); + db_->Close(); - TruncateDatabase(); + ASSERT_TRUE(TruncateDatabase()); - ASSERT_TRUE(db().Open(db_path())); - ASSERT_TRUE(db().Raze()); - EXPECT_EQ(0, SqliteMasterCount(&db())); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_TRUE(db_->Raze()); + EXPECT_EQ(0, SqliteMasterCount(db_.get())); } // Verify that Raze() can handle a file of junk. // Need exclusive mode off here as there are some subtleties (by design) around // how the cache is used with it on which causes the test to fail. TEST_P(SQLDatabaseTest, RazeNOTADB) { - db().Close(); - sql::Database::Delete(db_path()); - ASSERT_FALSE(GetPathExists(db_path())); + db_->Close(); + Database::Delete(db_path_); + ASSERT_FALSE(base::PathExists(db_path_)); - WriteJunkToDatabase(SQLTestBase::TYPE_OVERWRITE_AND_TRUNCATE); - ASSERT_TRUE(GetPathExists(db_path())); + ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kTruncate)); + ASSERT_TRUE(base::PathExists(db_path_)); // SQLite will successfully open the handle, but fail when running PRAGMA // statements that access the database. @@ -609,25 +645,25 @@ TEST_P(SQLDatabaseTest, RazeNOTADB) { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_NOTADB); - EXPECT_TRUE(db().Open(db_path())); + EXPECT_TRUE(db_->Open(db_path_)); ASSERT_TRUE(expecter.SawExpectedErrors()); } - EXPECT_TRUE(db().Raze()); - db().Close(); + EXPECT_TRUE(db_->Raze()); + db_->Close(); // Now empty, the open should open an empty database. - EXPECT_TRUE(db().Open(db_path())); - EXPECT_EQ(0, SqliteMasterCount(&db())); + EXPECT_TRUE(db_->Open(db_path_)); + EXPECT_EQ(0, SqliteMasterCount(db_.get())); } // Verify that Raze() can handle a database overwritten with garbage. TEST_P(SQLDatabaseTest, RazeNOTADB2) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_EQ(1, SqliteMasterCount(&db())); - db().Close(); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_EQ(1, SqliteMasterCount(db_.get())); + db_->Close(); - WriteJunkToDatabase(SQLTestBase::TYPE_OVERWRITE); + ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kOverwrite)); // SQLite will successfully open the handle, but will fail with // SQLITE_NOTADB on pragma statemenets which attempt to read the @@ -635,15 +671,15 @@ TEST_P(SQLDatabaseTest, RazeNOTADB2) { { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_NOTADB); - EXPECT_TRUE(db().Open(db_path())); + EXPECT_TRUE(db_->Open(db_path_)); ASSERT_TRUE(expecter.SawExpectedErrors()); } - EXPECT_TRUE(db().Raze()); - db().Close(); + EXPECT_TRUE(db_->Raze()); + db_->Close(); // Now empty, the open should succeed with an empty database. - EXPECT_TRUE(db().Open(db_path())); - EXPECT_EQ(0, SqliteMasterCount(&db())); + EXPECT_TRUE(db_->Open(db_path_)); + EXPECT_EQ(0, SqliteMasterCount(db_.get())); } // Test that a callback from Open() can raze the database. This is @@ -652,34 +688,34 @@ TEST_P(SQLDatabaseTest, RazeNOTADB2) { // callback does this during Open(), the open is retried and succeeds. TEST_P(SQLDatabaseTest, RazeCallbackReopen) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_EQ(1, SqliteMasterCount(&db())); - db().Close(); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_EQ(1, SqliteMasterCount(db_.get())); + db_->Close(); // Corrupt the database so that nothing works, including PRAGMAs. - ASSERT_TRUE(CorruptSizeInHeaderOfDB()); + ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_)); // Open() will succeed, even though the PRAGMA calls within will // fail with SQLITE_CORRUPT, as will this PRAGMA. { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db().Open(db_path())); - ASSERT_FALSE(db().Execute("PRAGMA auto_vacuum")); - db().Close(); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_FALSE(db_->Execute("PRAGMA auto_vacuum")); + db_->Close(); ASSERT_TRUE(expecter.SawExpectedErrors()); } - db().set_error_callback( - base::BindRepeating(&RazeErrorCallback, &db(), SQLITE_CORRUPT)); + db_->set_error_callback( + base::BindRepeating(&RazeErrorCallback, db_.get(), SQLITE_CORRUPT)); // When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error // callback will call RazeAndClose(). Open() will then fail and be // retried. The second Open() on the empty database will succeed // cleanly. - ASSERT_TRUE(db().Open(db_path())); - ASSERT_TRUE(db().Execute("PRAGMA auto_vacuum")); - EXPECT_EQ(0, SqliteMasterCount(&db())); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_TRUE(db_->Execute("PRAGMA auto_vacuum")); + EXPECT_EQ(0, SqliteMasterCount(db_.get())); } // Basic test of RazeAndClose() operation. @@ -689,24 +725,24 @@ TEST_P(SQLDatabaseTest, RazeAndClose) { // Test that RazeAndClose() closes the database, and that the // database is empty when re-opened. - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kPopulateSql)); - ASSERT_TRUE(db().RazeAndClose()); - ASSERT_FALSE(db().is_open()); - db().Close(); - ASSERT_TRUE(db().Open(db_path())); - ASSERT_EQ(0, SqliteMasterCount(&db())); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kPopulateSql)); + ASSERT_TRUE(db_->RazeAndClose()); + ASSERT_FALSE(db_->is_open()); + db_->Close(); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_EQ(0, SqliteMasterCount(db_.get())); // Test that RazeAndClose() can break transactions. - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kPopulateSql)); - ASSERT_TRUE(db().BeginTransaction()); - ASSERT_TRUE(db().RazeAndClose()); - ASSERT_FALSE(db().is_open()); - ASSERT_FALSE(db().CommitTransaction()); - db().Close(); - ASSERT_TRUE(db().Open(db_path())); - ASSERT_EQ(0, SqliteMasterCount(&db())); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kPopulateSql)); + ASSERT_TRUE(db_->BeginTransaction()); + ASSERT_TRUE(db_->RazeAndClose()); + ASSERT_FALSE(db_->is_open()); + ASSERT_FALSE(db_->CommitTransaction()); + db_->Close(); + ASSERT_TRUE(db_->Open(db_path_)); + ASSERT_EQ(0, SqliteMasterCount(db_.get())); } // Test that various operations fail without crashing after @@ -716,53 +752,53 @@ TEST_P(SQLDatabaseTest, RazeAndCloseDiagnostics) { const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)"; const char* kSimpleSql = "SELECT 1"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kPopulateSql)); + ASSERT_TRUE(db_->Execute(kCreateSql)); + ASSERT_TRUE(db_->Execute(kPopulateSql)); // Test baseline expectations. - db().Preload(); - ASSERT_TRUE(db().DoesTableExist("foo")); - ASSERT_TRUE(db().IsSQLValid(kSimpleSql)); - ASSERT_EQ(SQLITE_OK, db().ExecuteAndReturnErrorCode(kSimpleSql)); - ASSERT_TRUE(db().Execute(kSimpleSql)); - ASSERT_TRUE(db().is_open()); + db_->Preload(); + ASSERT_TRUE(db_->DoesTableExist("foo")); + ASSERT_TRUE(db_->IsSQLValid(kSimpleSql)); + ASSERT_EQ(SQLITE_OK, db_->ExecuteAndReturnErrorCode(kSimpleSql)); + ASSERT_TRUE(db_->Execute(kSimpleSql)); + ASSERT_TRUE(db_->is_open()); { - sql::Statement s(db().GetUniqueStatement(kSimpleSql)); + Statement s(db_->GetUniqueStatement(kSimpleSql)); ASSERT_TRUE(s.Step()); } { - sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); + Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); ASSERT_TRUE(s.Step()); } - ASSERT_TRUE(db().BeginTransaction()); - ASSERT_TRUE(db().CommitTransaction()); - ASSERT_TRUE(db().BeginTransaction()); - db().RollbackTransaction(); + ASSERT_TRUE(db_->BeginTransaction()); + ASSERT_TRUE(db_->CommitTransaction()); + ASSERT_TRUE(db_->BeginTransaction()); + db_->RollbackTransaction(); - ASSERT_TRUE(db().RazeAndClose()); + ASSERT_TRUE(db_->RazeAndClose()); // At this point, they should all fail, but not crash. - db().Preload(); - ASSERT_FALSE(db().DoesTableExist("foo")); - ASSERT_FALSE(db().IsSQLValid(kSimpleSql)); - ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode(kSimpleSql)); - ASSERT_FALSE(db().Execute(kSimpleSql)); - ASSERT_FALSE(db().is_open()); + db_->Preload(); + ASSERT_FALSE(db_->DoesTableExist("foo")); + ASSERT_FALSE(db_->IsSQLValid(kSimpleSql)); + ASSERT_EQ(SQLITE_ERROR, db_->ExecuteAndReturnErrorCode(kSimpleSql)); + ASSERT_FALSE(db_->Execute(kSimpleSql)); + ASSERT_FALSE(db_->is_open()); { - sql::Statement s(db().GetUniqueStatement(kSimpleSql)); + Statement s(db_->GetUniqueStatement(kSimpleSql)); ASSERT_FALSE(s.Step()); } { - sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); + Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); ASSERT_FALSE(s.Step()); } - ASSERT_FALSE(db().BeginTransaction()); - ASSERT_FALSE(db().CommitTransaction()); - ASSERT_FALSE(db().BeginTransaction()); - db().RollbackTransaction(); + ASSERT_FALSE(db_->BeginTransaction()); + ASSERT_FALSE(db_->CommitTransaction()); + ASSERT_FALSE(db_->BeginTransaction()); + db_->RollbackTransaction(); // Close normally to reset the poisoned flag. - db().Close(); + db_->Close(); // DEATH tests not supported on Android, iOS, or Fuchsia. #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA) @@ -770,7 +806,7 @@ TEST_P(SQLDatabaseTest, RazeAndCloseDiagnostics) { // usage by becoming fatal in debug mode. Since DEATH tests are // expensive, just test one of them. if (DLOG_IS_ON(FATAL)) { - ASSERT_DEATH({ db().IsSQLValid(kSimpleSql); }, + ASSERT_DEATH({ db_->IsSQLValid(kSimpleSql); }, "Illegal use of Database without a db"); } #endif // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA) @@ -789,75 +825,75 @@ TEST_P(SQLDatabaseTest, 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()); + ASSERT_TRUE(db_->Raze()); int64_t expected_size; - ASSERT_TRUE(base::GetFileSize(db_path(), &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)); + ASSERT_TRUE(db_->Execute(kCreateSql)); for (size_t i = 0; i < 24; ++i) { ASSERT_TRUE( - db().Execute("INSERT INTO foo (value) VALUES (randomblob(1024))")); + db_->Execute("INSERT INTO foo (value) VALUES (randomblob(1024))")); } // In WAL mode, writes don't reach the database file until a checkpoint // happens. - ASSERT_TRUE(db().CheckpointDatabase()); + ASSERT_TRUE(db_->CheckpointDatabase()); int64_t db_size; - ASSERT_TRUE(base::GetFileSize(db_path(), &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")); + ExecuteWithResult(db_.get(), "SELECT SUM(LENGTH(value)) FROM foo")); - ASSERT_TRUE(db().Raze()); - ASSERT_TRUE(base::GetFileSize(db_path(), &db_size)); + ASSERT_TRUE(db_->Raze()); + ASSERT_TRUE(base::GetFileSize(db_path_, &db_size)); ASSERT_EQ(expected_size, db_size); } #if defined(OS_ANDROID) TEST_P(SQLDatabaseTest, SetTempDirForSQL) { - sql::MetaTable meta_table; + MetaTable meta_table; // Below call needs a temporary directory in sqlite3 // On Android, it can pass only when the temporary directory is set. // Otherwise, sqlite3 doesn't find the correct directory to store // temporary files and will report the error 'unable to open // database file'. - ASSERT_TRUE(meta_table.Init(&db(), 4, 4)); + ASSERT_TRUE(meta_table.Init(db_.get(), 4, 4)); } #endif // defined(OS_ANDROID) TEST_P(SQLDatabaseTest, Delete) { - EXPECT_TRUE(db().Execute("CREATE TABLE x (x)")); - db().Close(); + EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)")); + db_->Close(); - base::FilePath journal_path = sql::Database::JournalPath(db_path()); - base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path()); + base::FilePath journal_path = Database::JournalPath(db_path_); + base::FilePath wal_path = Database::WriteAheadLogPath(db_path_); // Should have both a main database file and a journal file if // journal_mode is TRUNCATE. There is no WAL file as it is deleted on Close. - ASSERT_TRUE(GetPathExists(db_path())); + ASSERT_TRUE(base::PathExists(db_path_)); if (!IsWALEnabled()) { // TRUNCATE mode - ASSERT_TRUE(GetPathExists(journal_path)); + ASSERT_TRUE(base::PathExists(journal_path)); } - sql::Database::Delete(db_path()); - EXPECT_FALSE(GetPathExists(db_path())); - EXPECT_FALSE(GetPathExists(journal_path)); - EXPECT_FALSE(GetPathExists(wal_path)); + Database::Delete(db_path_); + EXPECT_FALSE(base::PathExists(db_path_)); + EXPECT_FALSE(base::PathExists(journal_path)); + EXPECT_FALSE(base::PathExists(wal_path)); } #if defined(OS_POSIX) // This test operates on POSIX file permissions. TEST_P(SQLDatabaseTest, PosixFilePermissions) { - db().Close(); - sql::Database::Delete(db_path()); - ASSERT_FALSE(GetPathExists(db_path())); + db_->Close(); + Database::Delete(db_path_); + ASSERT_FALSE(base::PathExists(db_path_)); // If the bots all had a restrictive umask setting such that databases are // always created with only the owner able to read them, then the code could @@ -865,37 +901,37 @@ TEST_P(SQLDatabaseTest, PosixFilePermissions) { // umask. ScopedUmaskSetter permissive_umask(S_IWGRP | S_IWOTH); - ASSERT_TRUE(db().Open(db_path())); + ASSERT_TRUE(db_->Open(db_path_)); // Cause the journal file to be created. If the default journal_mode is // changed back to DELETE, this test will need to be updated. - EXPECT_TRUE(db().Execute("CREATE TABLE x (x)")); + EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)")); int mode; - ASSERT_TRUE(GetPathExists(db_path())); - EXPECT_TRUE(base::GetPosixFilePermissions(db_path(), &mode)); + ASSERT_TRUE(base::PathExists(db_path_)); + EXPECT_TRUE(base::GetPosixFilePermissions(db_path_, &mode)); ASSERT_EQ(mode, 0600); if (IsWALEnabled()) { // WAL mode // The WAL file is created lazily on first change. - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); - base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path()); - ASSERT_TRUE(GetPathExists(wal_path)); + base::FilePath wal_path = Database::WriteAheadLogPath(db_path_); + ASSERT_TRUE(base::PathExists(wal_path)); EXPECT_TRUE(base::GetPosixFilePermissions(wal_path, &mode)); ASSERT_EQ(mode, 0600); // The shm file doesn't exist in exclusive locking mode. - if (ExecuteWithResult(&db(), "PRAGMA locking_mode") == "normal") { - base::FilePath shm_path = sql::Database::SharedMemoryFilePath(db_path()); - ASSERT_TRUE(GetPathExists(shm_path)); + if (ExecuteWithResult(db_.get(), "PRAGMA locking_mode") == "normal") { + base::FilePath shm_path = Database::SharedMemoryFilePath(db_path_); + ASSERT_TRUE(base::PathExists(shm_path)); EXPECT_TRUE(base::GetPosixFilePermissions(shm_path, &mode)); ASSERT_EQ(mode, 0600); } } else { // Truncate mode - base::FilePath journal_path = sql::Database::JournalPath(db_path()); + base::FilePath journal_path = Database::JournalPath(db_path_); DLOG(ERROR) << "journal_path: " << journal_path; - ASSERT_TRUE(GetPathExists(journal_path)); + ASSERT_TRUE(base::PathExists(journal_path)); EXPECT_TRUE(base::GetPosixFilePermissions(journal_path, &mode)); ASSERT_EQ(mode, 0600); } @@ -904,31 +940,31 @@ TEST_P(SQLDatabaseTest, PosixFilePermissions) { // Test that errors start happening once Poison() is called. TEST_P(SQLDatabaseTest, Poison) { - EXPECT_TRUE(db().Execute("CREATE TABLE x (x)")); + EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)")); // Before the Poison() call, things generally work. - EXPECT_TRUE(db().IsSQLValid("INSERT INTO x VALUES ('x')")); - EXPECT_TRUE(db().Execute("INSERT INTO x VALUES ('x')")); + EXPECT_TRUE(db_->IsSQLValid("INSERT INTO x VALUES ('x')")); + EXPECT_TRUE(db_->Execute("INSERT INTO x VALUES ('x')")); { - sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM x")); + Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM x")); ASSERT_TRUE(s.is_valid()); ASSERT_TRUE(s.Step()); } // Get a statement which is valid before and will exist across Poison(). - sql::Statement valid_statement( - db().GetUniqueStatement("SELECT COUNT(*) FROM sqlite_master")); + Statement valid_statement( + db_->GetUniqueStatement("SELECT COUNT(*) FROM sqlite_master")); ASSERT_TRUE(valid_statement.is_valid()); ASSERT_TRUE(valid_statement.Step()); valid_statement.Reset(true); - db().Poison(); + db_->Poison(); // After the Poison() call, things fail. - EXPECT_FALSE(db().IsSQLValid("INSERT INTO x VALUES ('x')")); - EXPECT_FALSE(db().Execute("INSERT INTO x VALUES ('x')")); + EXPECT_FALSE(db_->IsSQLValid("INSERT INTO x VALUES ('x')")); + EXPECT_FALSE(db_->Execute("INSERT INTO x VALUES ('x')")); { - sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM x")); + Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM x")); ASSERT_FALSE(s.is_valid()); ASSERT_FALSE(s.Step()); } @@ -939,77 +975,77 @@ TEST_P(SQLDatabaseTest, Poison) { // Test that poisoning the database during a transaction works (with errors). // RazeErrorCallback() poisons the database, the extra COMMIT causes - // CommitTransaction() to throw an error while commiting. - db().set_error_callback( - base::BindRepeating(&RazeErrorCallback, &db(), SQLITE_ERROR)); - db().Close(); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_TRUE(db().BeginTransaction()); - EXPECT_TRUE(db().Execute("INSERT INTO x VALUES ('x')")); - EXPECT_TRUE(db().Execute("COMMIT")); - EXPECT_FALSE(db().CommitTransaction()); + // CommitTransaction() to throw an error while committing. + db_->set_error_callback( + base::BindRepeating(&RazeErrorCallback, db_.get(), SQLITE_ERROR)); + db_->Close(); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_TRUE(db_->BeginTransaction()); + EXPECT_TRUE(db_->Execute("INSERT INTO x VALUES ('x')")); + EXPECT_TRUE(db_->Execute("COMMIT")); + EXPECT_FALSE(db_->CommitTransaction()); } TEST_P(SQLDatabaseTest, AttachDatabase) { - EXPECT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + EXPECT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); // Create a database to attach to. base::FilePath attach_path = - db_path().DirName().AppendASCII("SQLDatabaseAttach.db"); + db_path_.DirName().AppendASCII("SQLDatabaseAttach.db"); static const char kAttachmentPoint[] = "other"; { - sql::Database other_db; + Database other_db; ASSERT_TRUE(other_db.Open(attach_path)); EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)")); EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')")); } // Cannot see the attached database, yet. - EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar")); - EXPECT_TRUE( - DatabaseTestPeer::AttachDatabase(&db(), attach_path, kAttachmentPoint)); - EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path, + kAttachmentPoint)); + EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar")); // Queries can touch both databases after the ATTACH. - EXPECT_TRUE(db().Execute("INSERT INTO foo SELECT a, b FROM other.bar")); + EXPECT_TRUE(db_->Execute("INSERT INTO foo SELECT a, b FROM other.bar")); { - sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM foo")); + Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM foo")); ASSERT_TRUE(s.Step()); EXPECT_EQ(1, s.ColumnInt(0)); } - EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(&db(), kAttachmentPoint)); - EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint)); + EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar")); } TEST_P(SQLDatabaseTest, AttachDatabaseWithOpenTransaction) { - EXPECT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + EXPECT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); // Create a database to attach to. base::FilePath attach_path = - db_path().DirName().AppendASCII("SQLDatabaseAttach.db"); + db_path_.DirName().AppendASCII("SQLDatabaseAttach.db"); static const char kAttachmentPoint[] = "other"; { - sql::Database other_db; + Database other_db; ASSERT_TRUE(other_db.Open(attach_path)); EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)")); EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')")); } // Cannot see the attached database, yet. - EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar")); // Attach succeeds in a transaction. - EXPECT_TRUE(db().BeginTransaction()); - EXPECT_TRUE( - DatabaseTestPeer::AttachDatabase(&db(), attach_path, kAttachmentPoint)); - EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_TRUE(db_->BeginTransaction()); + EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path, + kAttachmentPoint)); + EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar")); // Queries can touch both databases after the ATTACH. - EXPECT_TRUE(db().Execute("INSERT INTO foo SELECT a, b FROM other.bar")); + EXPECT_TRUE(db_->Execute("INSERT INTO foo SELECT a, b FROM other.bar")); { - sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM foo")); + Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM foo")); ASSERT_TRUE(s.Step()); EXPECT_EQ(1, s.ColumnInt(0)); } @@ -1018,30 +1054,30 @@ TEST_P(SQLDatabaseTest, AttachDatabaseWithOpenTransaction) { { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_ERROR); - EXPECT_FALSE(DatabaseTestPeer::DetachDatabase(&db(), kAttachmentPoint)); - EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar")); + EXPECT_FALSE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint)); + EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar")); ASSERT_TRUE(expecter.SawExpectedErrors()); } // Detach succeeds when the transaction is closed. - db().RollbackTransaction(); - EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(&db(), kAttachmentPoint)); - EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar")); + db_->RollbackTransaction(); + EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint)); + EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar")); } TEST_P(SQLDatabaseTest, Basic_QuickIntegrityCheck) { const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - EXPECT_TRUE(db().QuickIntegrityCheck()); - db().Close(); + ASSERT_TRUE(db_->Execute(kCreateSql)); + EXPECT_TRUE(db_->QuickIntegrityCheck()); + db_->Close(); - ASSERT_TRUE(CorruptSizeInHeaderOfDB()); + ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_)); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_FALSE(db().QuickIntegrityCheck()); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_FALSE(db_->QuickIntegrityCheck()); ASSERT_TRUE(expecter.SawExpectedErrors()); } } @@ -1051,19 +1087,19 @@ TEST_P(SQLDatabaseTest, Basic_FullIntegrityCheck) { std::vector<std::string> messages; const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - EXPECT_TRUE(db().FullIntegrityCheck(&messages)); + ASSERT_TRUE(db_->Execute(kCreateSql)); + EXPECT_TRUE(db_->FullIntegrityCheck(&messages)); EXPECT_EQ(1u, messages.size()); EXPECT_EQ(kOk, messages[0]); - db().Close(); + db_->Close(); - ASSERT_TRUE(CorruptSizeInHeaderOfDB()); + ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_)); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_TRUE(db().FullIntegrityCheck(&messages)); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_TRUE(db_->FullIntegrityCheck(&messages)); EXPECT_LT(1u, messages.size()); EXPECT_NE(kOk, messages[0]); ASSERT_TRUE(expecter.SawExpectedErrors()); @@ -1077,38 +1113,38 @@ TEST_P(SQLDatabaseTest, OnMemoryDump) { base::trace_event::MemoryDumpArgs args = { base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; base::trace_event::ProcessMemoryDump pmd(args); - ASSERT_TRUE(db().memory_dump_provider_->OnMemoryDump(args, &pmd)); + ASSERT_TRUE(db_->memory_dump_provider_->OnMemoryDump(args, &pmd)); EXPECT_GE(pmd.allocator_dumps().size(), 1u); } // Test that the functions to collect diagnostic data run to completion, without // worrying too much about what they generate (since that will change). TEST_P(SQLDatabaseTest, CollectDiagnosticInfo) { - const std::string corruption_info = db().CollectCorruptionInfo(); + const std::string corruption_info = db_->CollectCorruptionInfo(); EXPECT_NE(std::string::npos, corruption_info.find("SQLITE_CORRUPT")); EXPECT_NE(std::string::npos, corruption_info.find("integrity_check")); // A statement to see in the results. const char* kSimpleSql = "SELECT 'mountain'"; - Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); + Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); // Error includes the statement. - const std::string readonly_info = db().CollectErrorInfo(SQLITE_READONLY, &s); + const std::string readonly_info = db_->CollectErrorInfo(SQLITE_READONLY, &s); EXPECT_NE(std::string::npos, readonly_info.find(kSimpleSql)); // Some other error doesn't include the statment. // TODO(shess): This is weak. - const std::string full_info = db().CollectErrorInfo(SQLITE_FULL, nullptr); + const std::string full_info = db_->CollectErrorInfo(SQLITE_FULL, nullptr); EXPECT_EQ(std::string::npos, full_info.find(kSimpleSql)); // A table to see in the SQLITE_ERROR results. - EXPECT_TRUE(db().Execute("CREATE TABLE volcano (x)")); + EXPECT_TRUE(db_->Execute("CREATE TABLE volcano (x)")); // Version info to see in the SQLITE_ERROR results. - sql::MetaTable meta_table; - ASSERT_TRUE(meta_table.Init(&db(), 4, 4)); + MetaTable meta_table; + ASSERT_TRUE(meta_table.Init(db_.get(), 4, 4)); - const std::string error_info = db().CollectErrorInfo(SQLITE_ERROR, &s); + const std::string error_info = db_->CollectErrorInfo(SQLITE_ERROR, &s); EXPECT_NE(std::string::npos, error_info.find(kSimpleSql)); EXPECT_NE(std::string::npos, error_info.find("volcano")); EXPECT_NE(std::string::npos, error_info.find("version: 4")); @@ -1118,7 +1154,7 @@ TEST_P(SQLDatabaseTest, CollectDiagnosticInfo) { // enabled by SQLite. TEST_P(SQLDatabaseTest, MmapInitiallyEnabled) { { - sql::Statement s(db().GetUniqueStatement("PRAGMA mmap_size")); + Statement s(db_->GetUniqueStatement("PRAGMA mmap_size")); ASSERT_TRUE(s.Step()) << "All supported SQLite versions should have mmap support"; @@ -1127,7 +1163,7 @@ TEST_P(SQLDatabaseTest, MmapInitiallyEnabled) { // returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for // instance MojoVFS), -1 is returned. if (s.ColumnInt(0) <= 0) { - ASSERT_TRUE(db().Execute("PRAGMA mmap_size = 1048576")); + ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576")); s.Reset(true); ASSERT_TRUE(s.Step()); EXPECT_LE(s.ColumnInt(0), 0); @@ -1135,24 +1171,24 @@ TEST_P(SQLDatabaseTest, MmapInitiallyEnabled) { } // Test that explicit disable prevents mmap'ed I/O. - db().Close(); - sql::Database::Delete(db_path()); - db().set_mmap_disabled(); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_EQ("0", ExecuteWithResult(&db(), "PRAGMA mmap_size")); + db_->Close(); + Database::Delete(db_path_); + db_->set_mmap_disabled(); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_EQ("0", ExecuteWithResult(db_.get(), "PRAGMA mmap_size")); } // Test whether a fresh database gets mmap enabled when using alternate status // storage. TEST_P(SQLDatabaseTest, MmapInitiallyEnabledAltStatus) { // Re-open fresh database with alt-status flag set. - db().Close(); - sql::Database::Delete(db_path()); - db().set_mmap_alt_status(); - ASSERT_TRUE(db().Open(db_path())); + db_->Close(); + Database::Delete(db_path_); + db_->set_mmap_alt_status(); + ASSERT_TRUE(db_->Open(db_path_)); { - sql::Statement s(db().GetUniqueStatement("PRAGMA mmap_size")); + Statement s(db_->GetUniqueStatement("PRAGMA mmap_size")); ASSERT_TRUE(s.Step()) << "All supported SQLite versions should have mmap support"; @@ -1161,7 +1197,7 @@ TEST_P(SQLDatabaseTest, MmapInitiallyEnabledAltStatus) { // returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for // instance MojoVFS), -1 is returned. if (s.ColumnInt(0) <= 0) { - ASSERT_TRUE(db().Execute("PRAGMA mmap_size = 1048576")); + ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576")); s.Reset(true); ASSERT_TRUE(s.Step()); EXPECT_LE(s.ColumnInt(0), 0); @@ -1169,11 +1205,11 @@ TEST_P(SQLDatabaseTest, MmapInitiallyEnabledAltStatus) { } // Test that explicit disable overrides set_mmap_alt_status(). - db().Close(); - sql::Database::Delete(db_path()); - db().set_mmap_disabled(); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_EQ("0", ExecuteWithResult(&db(), "PRAGMA mmap_size")); + db_->Close(); + Database::Delete(db_path_); + db_->set_mmap_disabled(); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_EQ("0", ExecuteWithResult(db_.get(), "PRAGMA mmap_size")); } TEST_P(SQLDatabaseTest, GetAppropriateMmapSize) { @@ -1182,40 +1218,40 @@ TEST_P(SQLDatabaseTest, GetAppropriateMmapSize) { // If there is no meta table (as for a fresh database), assume that everything // should be mapped, and the status of the meta table is not affected. - ASSERT_TRUE(!db().DoesTableExist("meta")); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_TRUE(!db().DoesTableExist("meta")); + ASSERT_TRUE(!db_->DoesTableExist("meta")); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_TRUE(!db_->DoesTableExist("meta")); // When the meta table is first created, it sets up to map everything. - MetaTable().Init(&db(), 1, 1); - ASSERT_TRUE(db().DoesTableExist("meta")); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_TRUE(MetaTable::GetMmapStatus(&db(), &mmap_status)); + MetaTable().Init(db_.get(), 1, 1); + ASSERT_TRUE(db_->DoesTableExist("meta")); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status)); ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status); // Preload with partial progress of one page. Should map everything. - ASSERT_TRUE(db().Execute("REPLACE INTO meta VALUES ('mmap_status', 1)")); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_TRUE(MetaTable::GetMmapStatus(&db(), &mmap_status)); + ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', 1)")); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status)); ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status); // Failure status maps nothing. - ASSERT_TRUE(db().Execute("REPLACE INTO meta VALUES ('mmap_status', -2)")); - ASSERT_EQ(0UL, db().GetAppropriateMmapSize()); + ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', -2)")); + ASSERT_EQ(0UL, db_->GetAppropriateMmapSize()); // Re-initializing the meta table does not re-create the key if the table // already exists. - ASSERT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'mmap_status'")); - MetaTable().Init(&db(), 1, 1); + ASSERT_TRUE(db_->Execute("DELETE FROM meta WHERE key = 'mmap_status'")); + MetaTable().Init(db_.get(), 1, 1); ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status); - ASSERT_TRUE(MetaTable::GetMmapStatus(&db(), &mmap_status)); + ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status)); ASSERT_EQ(0, mmap_status); // With no key, map everything and create the key. // TODO(shess): This really should be "maps everything after validating it", // but that is more complicated to structure. - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_TRUE(MetaTable::GetMmapStatus(&db(), &mmap_status)); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status)); ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status); } @@ -1223,133 +1259,151 @@ TEST_P(SQLDatabaseTest, GetAppropriateMmapSizeAltStatus) { const size_t kMmapAlot = 25 * 1024 * 1024; // At this point, Database still expects a future [meta] table. - ASSERT_FALSE(db().DoesTableExist("meta")); - ASSERT_FALSE(db().DoesViewExist("MmapStatus")); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_FALSE(db().DoesTableExist("meta")); - ASSERT_FALSE(db().DoesViewExist("MmapStatus")); + ASSERT_FALSE(db_->DoesTableExist("meta")); + ASSERT_FALSE(db_->DoesViewExist("MmapStatus")); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_FALSE(db_->DoesTableExist("meta")); + ASSERT_FALSE(db_->DoesViewExist("MmapStatus")); // Using alt status, everything should be mapped, with state in the view. - db().set_mmap_alt_status(); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); - ASSERT_FALSE(db().DoesTableExist("meta")); - ASSERT_TRUE(db().DoesViewExist("MmapStatus")); + db_->set_mmap_alt_status(); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); + ASSERT_FALSE(db_->DoesTableExist("meta")); + ASSERT_TRUE(db_->DoesViewExist("MmapStatus")); EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess), - ExecuteWithResult(&db(), "SELECT * FROM MmapStatus")); + ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus")); // Also maps everything when kMmapSuccess is already in the view. - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); // Preload with partial progress of one page. Should map everything. - ASSERT_TRUE(db().Execute("DROP VIEW MmapStatus")); - ASSERT_TRUE(db().Execute("CREATE VIEW MmapStatus (value) AS SELECT 1")); - ASSERT_GT(db().GetAppropriateMmapSize(), kMmapAlot); + ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus")); + ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT 1")); + ASSERT_GT(db_->GetAppropriateMmapSize(), kMmapAlot); EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess), - ExecuteWithResult(&db(), "SELECT * FROM MmapStatus")); + ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus")); // Failure status leads to nothing being mapped. - ASSERT_TRUE(db().Execute("DROP VIEW MmapStatus")); - ASSERT_TRUE(db().Execute("CREATE VIEW MmapStatus (value) AS SELECT -2")); - ASSERT_EQ(0UL, db().GetAppropriateMmapSize()); + ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus")); + ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT -2")); + ASSERT_EQ(0UL, db_->GetAppropriateMmapSize()); EXPECT_EQ(base::NumberToString(MetaTable::kMmapFailure), - ExecuteWithResult(&db(), "SELECT * FROM MmapStatus")); + ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus")); } TEST_P(SQLDatabaseTest, GetMemoryUsage) { // Databases with mmap enabled may not follow the assumptions below. - db().Close(); - db().set_mmap_disabled(); - ASSERT_TRUE(db().Open(db_path())); + db_->Close(); + db_->set_mmap_disabled(); + ASSERT_TRUE(db_->Open(db_path_)); - int initial_memory = db().GetMemoryUsage(); + int initial_memory = db_->GetMemoryUsage(); EXPECT_GT(initial_memory, 0) << "SQLite should always use some memory for a database"; - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)")); - int post_query_memory = db().GetMemoryUsage(); + int post_query_memory = db_->GetMemoryUsage(); EXPECT_GT(post_query_memory, initial_memory) << "Page cache usage should go up after executing queries"; - db().TrimMemory(); - int post_trim_memory = db().GetMemoryUsage(); + db_->TrimMemory(); + int post_trim_memory = db_->GetMemoryUsage(); EXPECT_GT(post_query_memory, post_trim_memory) << "Page cache usage should go down after calling TrimMemory()"; } -class SQLDatabaseTestExclusiveMode : public SQLDatabaseTest { +class SQLDatabaseTestExclusiveMode : public testing::Test, + public testing::WithParamInterface<bool> { public: - SQLDatabaseTestExclusiveMode() : SQLDatabaseTest(GetDBOptions()) {} + ~SQLDatabaseTestExclusiveMode() override = default; + + void SetUp() override { + db_ = std::make_unique<Database>(GetDBOptions()); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_path_ = temp_dir_.GetPath().AppendASCII("recovery_test.sqlite"); + ASSERT_TRUE(db_->Open(db_path_)); + } DatabaseOptions GetDBOptions() { - DatabaseOptions options = SQLDatabaseTest::GetDBOptions(); + DatabaseOptions options; + options.wal_mode = IsWALEnabled(); options.exclusive_locking = true; return options; } + + bool IsWALEnabled() { return GetParam(); } + + protected: + base::ScopedTempDir temp_dir_; + base::FilePath db_path_; + std::unique_ptr<Database> db_; }; TEST_P(SQLDatabaseTestExclusiveMode, LockingModeExclusive) { - EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA locking_mode"), "exclusive"); + EXPECT_EQ(ExecuteWithResult(db_.get(), "PRAGMA locking_mode"), "exclusive"); } TEST_P(SQLDatabaseTest, LockingModeNormal) { - EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA locking_mode"), "normal"); + EXPECT_EQ(ExecuteWithResult(db_.get(), "PRAGMA locking_mode"), "normal"); } TEST_P(SQLDatabaseTest, OpenedInCorrectMode) { std::string expected_mode = IsWALEnabled() ? "wal" : "truncate"; - EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), expected_mode); + EXPECT_EQ(ExecuteWithResult(db_.get(), "PRAGMA journal_mode"), expected_mode); } TEST_P(SQLDatabaseTest, CheckpointDatabase) { if (!IsWALEnabled()) return; - base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path()); + base::FilePath wal_path = Database::WriteAheadLogPath(db_path_); int64_t wal_size = 0; // WAL file initially empty. - EXPECT_TRUE(GetPathExists(wal_path)); + EXPECT_TRUE(base::PathExists(wal_path)); base::GetFileSize(wal_path, &wal_size); EXPECT_EQ(wal_size, 0); ASSERT_TRUE( - db().Execute("CREATE TABLE foo (id INTEGER UNIQUE, value INTEGER)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo VALUES (1, 1)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo VALUES (2, 2)")); + db_->Execute("CREATE TABLE foo (id INTEGER UNIQUE, value INTEGER)")); + ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (1, 1)")); + ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (2, 2)")); // Writes reach WAL file but not db file. base::GetFileSize(wal_path, &wal_size); EXPECT_GT(wal_size, 0); int64_t db_size = 0; - base::GetFileSize(db_path(), &db_size); - EXPECT_EQ(db_size, db().page_size()); + base::GetFileSize(db_path_, &db_size); + EXPECT_EQ(db_size, db_->page_size()); // Checkpoint database to immediately propagate writes to DB file. - EXPECT_TRUE(db().CheckpointDatabase()); - - base::GetFileSize(db_path(), &db_size); - EXPECT_GT(db_size, db().page_size()); - EXPECT_EQ(ExecuteWithResult(&db(), "SELECT value FROM foo where id=1"), "1"); - EXPECT_EQ(ExecuteWithResult(&db(), "SELECT value FROM foo where id=2"), "2"); + EXPECT_TRUE(db_->CheckpointDatabase()); + + base::GetFileSize(db_path_, &db_size); + EXPECT_GT(db_size, db_->page_size()); + EXPECT_EQ(ExecuteWithResult(db_.get(), "SELECT value FROM foo where id=1"), + "1"); + EXPECT_EQ(ExecuteWithResult(db_.get(), "SELECT value FROM foo where id=2"), + "2"); } TEST_P(SQLDatabaseTest, CorruptSizeInHeaderTest) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (x)")); - ASSERT_TRUE(db().Execute("CREATE TABLE bar (x)")); - db().Close(); + ASSERT_TRUE(db_->Execute("CREATE TABLE foo (x)")); + ASSERT_TRUE(db_->Execute("CREATE TABLE bar (x)")); + db_->Close(); - ASSERT_TRUE(CorruptSizeInHeaderOfDB()); + ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_)); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db().Open(db_path())); - EXPECT_FALSE(db().Execute("INSERT INTO foo values (1)")); - EXPECT_FALSE(db().DoesTableExist("foo")); - EXPECT_FALSE(db().DoesTableExist("bar")); - EXPECT_FALSE(db().Execute("SELECT * FROM foo")); + ASSERT_TRUE(db_->Open(db_path_)); + EXPECT_FALSE(db_->Execute("INSERT INTO foo values (1)")); + EXPECT_FALSE(db_->DoesTableExist("foo")); + EXPECT_FALSE(db_->DoesTableExist("bar")); + EXPECT_FALSE(db_->Execute("SELECT * FROM foo")); EXPECT_TRUE(expecter.SawExpectedErrors()); } } @@ -1361,8 +1415,8 @@ TEST_P(SQLDatabaseTest, CompileError) { // DEATH tests not supported on Android, iOS, or Fuchsia. #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA) if (DLOG_IS_ON(FATAL)) { - db().set_error_callback(base::BindRepeating(&IgnoreErrorCallback)); - ASSERT_DEATH({ db().GetUniqueStatement("SELECT x"); }, + db_->set_error_callback(base::BindRepeating(&IgnoreErrorCallback)); + ASSERT_DEATH({ db_->GetUniqueStatement("SELECT x"); }, "SQL compile error no such column: x"); } #endif // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA) diff --git a/chromium/sql/initialization.cc b/chromium/sql/initialization.cc index 4fa0bc07342..58a1ed7a3da 100644 --- a/chromium/sql/initialization.cc +++ b/chromium/sql/initialization.cc @@ -9,6 +9,7 @@ #include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "third_party/sqlite/sqlite3.h" @@ -52,6 +53,7 @@ void EnsureSqliteInitialized() { static bool first_call = true; if (first_call) { + TRACE_EVENT0("sql", "EnsureSqliteInitialized"); sqlite3_initialize(); #if !defined(OS_IOS) diff --git a/chromium/sql/meta_table_unittest.cc b/chromium/sql/meta_table_unittest.cc index 928c0ed02da..e91380b2279 100644 --- a/chromium/sql/meta_table_unittest.cc +++ b/chromium/sql/meta_table_unittest.cc @@ -10,22 +10,36 @@ #include "base/files/scoped_temp_dir.h" #include "sql/database.h" #include "sql/statement.h" -#include "sql/test/sql_test_base.h" #include "testing/gtest/include/gtest/gtest.h" +namespace sql { + namespace { -using SQLMetaTableTest = sql::SQLTestBase; +class SQLMetaTableTest : public testing::Test { + public: + ~SQLMetaTableTest() override = default; + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + db_.Open(temp_dir_.GetPath().AppendASCII("meta_table_test.sqlite"))); + } + + protected: + base::ScopedTempDir temp_dir_; + Database db_; +}; TEST_F(SQLMetaTableTest, DoesTableExist) { - EXPECT_FALSE(sql::MetaTable::DoesTableExist(&db())); + EXPECT_FALSE(MetaTable::DoesTableExist(&db_)); { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); } - EXPECT_TRUE(sql::MetaTable::DoesTableExist(&db())); + EXPECT_TRUE(MetaTable::DoesTableExist(&db_)); } TEST_F(SQLMetaTableTest, RazeIfDeprecated) { @@ -34,45 +48,45 @@ TEST_F(SQLMetaTableTest, RazeIfDeprecated) { // Setup a current database. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kVersion, kVersion)); - EXPECT_TRUE(db().Execute("CREATE TABLE t(c)")); - EXPECT_TRUE(db().DoesTableExist("t")); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kVersion, kVersion)); + EXPECT_TRUE(db_.Execute("CREATE TABLE t(c)")); + EXPECT_TRUE(db_.DoesTableExist("t")); } // Table should should still exist if the database version is new enough. - sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion); - EXPECT_TRUE(db().DoesTableExist("t")); + MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion); + EXPECT_TRUE(db_.DoesTableExist("t")); // TODO(shess): It may make sense to Raze() if meta isn't present or // version isn't present. See meta_table.h TODO on RazeIfDeprecated(). // Table should still exist if the version is not available. - EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); + EXPECT_TRUE(db_.Execute("DELETE FROM meta WHERE key = 'version'")); { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kVersion, kVersion)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kVersion, kVersion)); EXPECT_EQ(0, meta_table.GetVersionNumber()); } - sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion); - EXPECT_TRUE(db().DoesTableExist("t")); + MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion); + EXPECT_TRUE(db_.DoesTableExist("t")); // Table should still exist if meta table is missing. - EXPECT_TRUE(db().Execute("DROP TABLE meta")); - sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion); - EXPECT_TRUE(db().DoesTableExist("t")); + EXPECT_TRUE(db_.Execute("DROP TABLE meta")); + MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion); + EXPECT_TRUE(db_.DoesTableExist("t")); // Setup meta with deprecated version. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kDeprecatedVersion, kDeprecatedVersion)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kDeprecatedVersion, kDeprecatedVersion)); } // Deprecation check should remove the table. - EXPECT_TRUE(db().DoesTableExist("t")); - sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion); - EXPECT_FALSE(sql::MetaTable::DoesTableExist(&db())); - EXPECT_FALSE(db().DoesTableExist("t")); + EXPECT_TRUE(db_.DoesTableExist("t")); + MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion); + EXPECT_FALSE(MetaTable::DoesTableExist(&db_)); + EXPECT_FALSE(db_.DoesTableExist("t")); } TEST_F(SQLMetaTableTest, VersionNumber) { @@ -87,16 +101,16 @@ TEST_F(SQLMetaTableTest, VersionNumber) { // First Init() sets the version info as expected. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kVersionFirst, kCompatVersionFirst)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kVersionFirst, kCompatVersionFirst)); EXPECT_EQ(kVersionFirst, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionFirst, meta_table.GetCompatibleVersionNumber()); } // Second Init() does not change the version info. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kVersionSecond, kCompatVersionSecond)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kVersionSecond, kCompatVersionSecond)); EXPECT_EQ(kVersionFirst, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionFirst, meta_table.GetCompatibleVersionNumber()); @@ -106,8 +120,8 @@ TEST_F(SQLMetaTableTest, VersionNumber) { // Version info from Set*() calls is seen. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), kVersionThird, kCompatVersionThird)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, kVersionThird, kCompatVersionThird)); EXPECT_EQ(kVersionSecond, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionSecond, meta_table.GetCompatibleVersionNumber()); } @@ -120,8 +134,8 @@ TEST_F(SQLMetaTableTest, StringValue) { // Initially, the value isn't there until set. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); @@ -133,8 +147,8 @@ TEST_F(SQLMetaTableTest, StringValue) { // Value is persistent across different instances. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -145,8 +159,8 @@ TEST_F(SQLMetaTableTest, StringValue) { // Existing value was successfully changed. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -161,8 +175,8 @@ TEST_F(SQLMetaTableTest, IntValue) { // Initially, the value isn't there until set. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); @@ -174,8 +188,8 @@ TEST_F(SQLMetaTableTest, IntValue) { // Value is persistent across different instances. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -186,8 +200,8 @@ TEST_F(SQLMetaTableTest, IntValue) { // Existing value was successfully changed. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -202,8 +216,8 @@ TEST_F(SQLMetaTableTest, Int64Value) { // Initially, the value isn't there until set. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); @@ -215,8 +229,8 @@ TEST_F(SQLMetaTableTest, Int64Value) { // Value is persistent across different instances. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -227,8 +241,8 @@ TEST_F(SQLMetaTableTest, Int64Value) { // Existing value was successfully changed. { - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); @@ -240,8 +254,8 @@ TEST_F(SQLMetaTableTest, DeleteKey) { static const char kKey[] = "String Key"; const std::string kValue("String Value"); - sql::MetaTable meta_table; - EXPECT_TRUE(meta_table.Init(&db(), 1, 1)); + MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); // Value isn't present. std::string value; @@ -258,3 +272,5 @@ TEST_F(SQLMetaTableTest, DeleteKey) { } } // namespace + +} // namespace sql diff --git a/chromium/sql/recover_module/module_unittest.cc b/chromium/sql/recover_module/module_unittest.cc index ba620b7fda6..2e0db47cf26 100644 --- a/chromium/sql/recover_module/module_unittest.cc +++ b/chromium/sql/recover_module/module_unittest.cc @@ -7,12 +7,12 @@ #include <tuple> #include <vector> +#include "base/files/scoped_temp_dir.h" #include "base/strings/stringprintf.h" #include "sql/database.h" #include "sql/statement.h" #include "sql/test/database_test_peer.h" #include "sql/test/scoped_error_expecter.h" -#include "sql/test/sql_test_base.h" #include "sql/test/test_helpers.h" #include "sql/transaction.h" #include "testing/gtest/include/gtest/gtest.h" @@ -21,123 +21,131 @@ namespace sql { namespace recover { -class RecoverModuleTest : public sql::SQLTestBase { +class RecoverModuleTest : public testing::Test { public: + ~RecoverModuleTest() override = default; + void SetUp() override { - SQLTestBase::SetUp(); - ASSERT_TRUE(DatabaseTestPeer::EnableRecoveryExtension(&db())); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + db_.Open(temp_dir_.GetPath().AppendASCII("recovery_test.sqlite"))); + ASSERT_TRUE(DatabaseTestPeer::EnableRecoveryExtension(&db_)); } + + protected: + base::ScopedTempDir temp_dir_; + sql::Database db_; }; TEST_F(RecoverModuleTest, CreateVtable) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); EXPECT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t TEXT)")); } TEST_F(RecoverModuleTest, CreateVtableWithDatabaseSpecifier) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); EXPECT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(main.backing, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(main.backing, t TEXT)")); } TEST_F(RecoverModuleTest, CreateVtableOnSqliteMaster) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); EXPECT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover(" - "sqlite_master, type TEXT, name TEXT, tbl_name TEXT, " - "rootpage INTEGER, sql TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover(" + "sqlite_master, type TEXT, name TEXT, tbl_name TEXT, " + "rootpage INTEGER, sql TEXT)")); } TEST_F(RecoverModuleTest, CreateVtableFailsOnNonTempTable) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); - EXPECT_FALSE(db().Execute( + EXPECT_FALSE(db_.Execute( "CREATE VIRTUAL TABLE recover_backing USING recover(backing, t TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingTable) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_CORRUPT); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_missing " - "USING recover(missing, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_missing " + "USING recover(missing, t TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, DISABLED_CreateVtableFailsOnMissingDatabase) { // TODO(pwnall): Enable test after removing incorrect DLOG(FATAL) from // sql::Statement::Execute(). - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_ERROR); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(db.backing, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(db.backing, t TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, CreateVtableFailsOnTableWithInvalidQualifier) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_CORRUPT); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing invalid, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing invalid, t TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, DISABLED_CreateVtableFailsOnMissingTableName) { // TODO(pwnall): Enable test after removing incorrect DLOG(FATAL) from // sql::Statement::Execute(). - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_ERROR); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(main., t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(main., t TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingSchemaSpec) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingDbName) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(.backing)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(.backing)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, ColumnTypeMappingAny) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); EXPECT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t ANY)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t ANY)")); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "t"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "t"); EXPECT_EQ("(nullptr)", column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_FALSE(column_info.has_non_null_constraint); @@ -145,13 +153,13 @@ TEST_F(RecoverModuleTest, ColumnTypeMappingAny) { EXPECT_FALSE(column_info.is_auto_incremented); } TEST_F(RecoverModuleTest, ColumnTypeMappingAnyNotNull) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); EXPECT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t ANY NOT NULL)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t ANY NOT NULL)")); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "t"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "t"); EXPECT_EQ("(nullptr)", column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_TRUE(column_info.has_non_null_constraint); @@ -159,58 +167,58 @@ TEST_F(RecoverModuleTest, ColumnTypeMappingAnyNotNull) { EXPECT_FALSE(column_info.is_auto_incremented); } TEST_F(RecoverModuleTest, ColumnTypeMappingAnyStrict) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t ANY STRICT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t ANY STRICT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, ColumnTypeExtraKeyword) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t INTEGER SOMETHING)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t INTEGER SOMETHING)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, ColumnTypeNotNullExtraKeyword) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t INTEGER NOT NULL SOMETHING)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t INTEGER NOT NULL SOMETHING)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, ColumnTypeDoubleTypes) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing " - "USING recover(backing, t INTEGER FLOAT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing " + "USING recover(backing, t INTEGER FLOAT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } TEST_F(RecoverModuleTest, ColumnTypeNotNullDoubleTypes) { - ASSERT_TRUE(db().Execute("CREATE TABLE backing(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)")); { sql::test::ScopedErrorExpecter error_expecter; error_expecter.ExpectError(SQLITE_MISUSE); EXPECT_FALSE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover(" - "backing, t INTEGER NOT NULL TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover(" + "backing, t INTEGER NOT NULL TEXT)")); EXPECT_TRUE(error_expecter.SawExpectedErrors()); } } @@ -220,30 +228,39 @@ class RecoverModuleColumnTypeMappingTest public ::testing::WithParamInterface< std::tuple<const char*, const char*, bool>> { public: + ~RecoverModuleColumnTypeMappingTest() override = default; + void SetUp() override { - RecoverModuleTest::SetUp(); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + db_.Open(temp_dir_.GetPath().AppendASCII("recovery_test.sqlite"))); + ASSERT_TRUE(DatabaseTestPeer::EnableRecoveryExtension(&db_)); + std::string sql = base::StringPrintf("CREATE TABLE backing(data %s)", SchemaType()); - ASSERT_TRUE(db().Execute(sql.c_str())); + ASSERT_TRUE(db_.Execute(sql.c_str())); } - protected: void CreateRecoveryTable(const char* suffix) { std::string sql = base::StringPrintf( "CREATE VIRTUAL TABLE temp.recover_backing " "USING recover(backing, data %s%s)", SchemaType(), suffix); - ASSERT_TRUE(db().Execute(sql.c_str())); + ASSERT_TRUE(db_.Execute(sql.c_str())); } const char* SchemaType() const { return std::get<0>(GetParam()); } const char* ExpectedType() const { return std::get<1>(GetParam()); } bool IsAlwaysNonNull() const { return std::get<2>(GetParam()); } + + protected: + base::ScopedTempDir temp_dir_; + sql::Database db_; }; TEST_P(RecoverModuleColumnTypeMappingTest, Unqualified) { CreateRecoveryTable(""); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "data"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data"); EXPECT_EQ(ExpectedType(), column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_EQ(IsAlwaysNonNull(), column_info.has_non_null_constraint); @@ -253,7 +270,7 @@ TEST_P(RecoverModuleColumnTypeMappingTest, Unqualified) { TEST_P(RecoverModuleColumnTypeMappingTest, NotNull) { CreateRecoveryTable(" NOT NULL"); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "data"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data"); EXPECT_EQ(ExpectedType(), column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_TRUE(column_info.has_non_null_constraint); @@ -263,7 +280,7 @@ TEST_P(RecoverModuleColumnTypeMappingTest, NotNull) { TEST_P(RecoverModuleColumnTypeMappingTest, Strict) { CreateRecoveryTable(" STRICT"); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "data"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data"); EXPECT_EQ(ExpectedType(), column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_EQ(IsAlwaysNonNull(), column_info.has_non_null_constraint); @@ -273,7 +290,7 @@ TEST_P(RecoverModuleColumnTypeMappingTest, Strict) { TEST_P(RecoverModuleColumnTypeMappingTest, StrictNotNull) { CreateRecoveryTable(" STRICT NOT NULL"); sql::test::ColumnInfo column_info = - sql::test::ColumnInfo::Create(&db(), "temp", "recover_backing", "data"); + sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data"); EXPECT_EQ(ExpectedType(), column_info.data_type); EXPECT_EQ("BINARY", column_info.collation_sequence); EXPECT_TRUE(column_info.has_non_null_constraint); @@ -305,12 +322,12 @@ void GenerateAlteredTable(sql::Database* db) { } // namespace TEST_F(RecoverModuleTest, ReadFromAlteredTableNullDefaults) { - GenerateAlteredTable(&db()); + GenerateAlteredTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_altered " - "USING recover(altered, t TEXT, i INTEGER)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_altered " + "USING recover(altered, t TEXT, i INTEGER)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT t, i FROM recover_altered ORDER BY rowid")); ASSERT_TRUE(statement.Step()); EXPECT_EQ("a", statement.ColumnString(0)); @@ -329,12 +346,12 @@ TEST_F(RecoverModuleTest, ReadFromAlteredTableNullDefaults) { } TEST_F(RecoverModuleTest, ReadFromAlteredTableSkipsNulls) { - GenerateAlteredTable(&db()); + GenerateAlteredTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_altered " - "USING recover(altered, t TEXT, i INTEGER NOT NULL)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_altered " + "USING recover(altered, t TEXT, i INTEGER NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT t, i FROM recover_altered ORDER BY rowid")); ASSERT_TRUE(statement.Step()); EXPECT_EQ("d", statement.ColumnString(0)); @@ -366,13 +383,13 @@ void GenerateSizedTable(sql::Database* db, } // namespace TEST_F(RecoverModuleTest, LeafNodes) { - GenerateSizedTable(&db(), 10, "Leaf-node-generating line "); + GenerateSizedTable(&db_, 10, "Leaf-node-generating line "); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_sized " - "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized " + "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); sql::Statement statement( - db().GetUniqueStatement("SELECT t, i FROM recover_sized ORDER BY rowid")); + db_.GetUniqueStatement("SELECT t, i FROM recover_sized ORDER BY rowid")); for (int i = 0; i < 10; ++i) { ASSERT_TRUE(statement.Step()); EXPECT_EQ(base::StringPrintf("Leaf-node-generating line %d", i), @@ -383,22 +400,22 @@ TEST_F(RecoverModuleTest, LeafNodes) { } TEST_F(RecoverModuleTest, EmptyTable) { - GenerateSizedTable(&db(), 0, ""); + GenerateSizedTable(&db_, 0, ""); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_sized " - "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized " + "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, t, i FROM recover_sized ORDER BY rowid")); EXPECT_FALSE(statement.Step()); } TEST_F(RecoverModuleTest, SingleLevelInteriorNodes) { - GenerateSizedTable(&db(), 100, "Interior-node-generating line "); + GenerateSizedTable(&db_, 100, "Interior-node-generating line "); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_sized " - "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized " + "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, t, i FROM recover_sized ORDER BY rowid")); for (int i = 0; i < 100; ++i) { ASSERT_TRUE(statement.Step()); @@ -411,12 +428,12 @@ TEST_F(RecoverModuleTest, SingleLevelInteriorNodes) { } TEST_F(RecoverModuleTest, MultiLevelInteriorNodes) { - GenerateSizedTable(&db(), 5000, "Interior-node-generating line "); + GenerateSizedTable(&db_, 5000, "Interior-node-generating line "); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_sized " - "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized " + "USING recover(sized, t TEXT, i INTEGER NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, t, i FROM recover_sized ORDER BY rowid")); for (int i = 0; i < 5000; ++i) { ASSERT_TRUE(statement.Step()); @@ -444,11 +461,11 @@ void GenerateTypesTable(sql::Database* db) { } // namespace TEST_F(RecoverModuleTest, Any) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value ANY)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value ANY)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -482,11 +499,11 @@ TEST_F(RecoverModuleTest, Any) { } TEST_F(RecoverModuleTest, Integers) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value INTEGER)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value INTEGER)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -503,11 +520,11 @@ TEST_F(RecoverModuleTest, Integers) { } TEST_F(RecoverModuleTest, NonNullIntegers) { - GenerateTypesTable(&db()); - ASSERT_TRUE(db().Execute( + GenerateTypesTable(&db_); + ASSERT_TRUE(db_.Execute( "CREATE VIRTUAL TABLE temp.recover_types " "USING recover(types, rowtype TEXT, value INTEGER NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -520,11 +537,11 @@ TEST_F(RecoverModuleTest, NonNullIntegers) { } TEST_F(RecoverModuleTest, Floats) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value FLOAT)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value FLOAT)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -546,11 +563,11 @@ TEST_F(RecoverModuleTest, Floats) { } TEST_F(RecoverModuleTest, NonNullFloats) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value FLOAT NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value FLOAT NOT NULL)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -568,11 +585,11 @@ TEST_F(RecoverModuleTest, NonNullFloats) { } TEST_F(RecoverModuleTest, FloatsStrict) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value FLOAT STRICT)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value FLOAT STRICT)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -589,11 +606,11 @@ TEST_F(RecoverModuleTest, FloatsStrict) { } TEST_F(RecoverModuleTest, NonNullFloatsStrict) { - GenerateTypesTable(&db()); - ASSERT_TRUE(db().Execute( + GenerateTypesTable(&db_); + ASSERT_TRUE(db_.Execute( "CREATE VIRTUAL TABLE temp.recover_types " "USING recover(types, rowtype TEXT, value FLOAT STRICT NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -606,11 +623,11 @@ TEST_F(RecoverModuleTest, NonNullFloatsStrict) { } TEST_F(RecoverModuleTest, Texts) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value TEXT)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value TEXT)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -634,11 +651,11 @@ TEST_F(RecoverModuleTest, Texts) { } TEST_F(RecoverModuleTest, NonNullTexts) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value TEXT NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value TEXT NOT NULL)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -658,11 +675,11 @@ TEST_F(RecoverModuleTest, NonNullTexts) { } TEST_F(RecoverModuleTest, TextsStrict) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value TEXT STRICT)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value TEXT STRICT)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -679,11 +696,11 @@ TEST_F(RecoverModuleTest, TextsStrict) { } TEST_F(RecoverModuleTest, NonNullTextsStrict) { - GenerateTypesTable(&db()); - ASSERT_TRUE(db().Execute( + GenerateTypesTable(&db_); + ASSERT_TRUE(db_.Execute( "CREATE VIRTUAL TABLE temp.recover_types " "USING recover(types, rowtype TEXT, value TEXT STRICT NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -696,11 +713,11 @@ TEST_F(RecoverModuleTest, NonNullTextsStrict) { } TEST_F(RecoverModuleTest, Blobs) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value BLOB)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value BLOB)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -719,11 +736,11 @@ TEST_F(RecoverModuleTest, Blobs) { } TEST_F(RecoverModuleTest, NonNullBlobs) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value BLOB NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value BLOB NOT NULL)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -738,11 +755,11 @@ TEST_F(RecoverModuleTest, NonNullBlobs) { } TEST_F(RecoverModuleTest, AnyNonNull) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_types " - "USING recover(types, rowtype TEXT, value ANY NOT NULL)")); - sql::Statement statement(db().GetUniqueStatement( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_types " + "USING recover(types, rowtype TEXT, value ANY NOT NULL)")); + sql::Statement statement(db_.GetUniqueStatement( "SELECT rowid, rowtype, value FROM recover_types")); ASSERT_TRUE(statement.Step()); @@ -772,20 +789,20 @@ TEST_F(RecoverModuleTest, AnyNonNull) { } TEST_F(RecoverModuleTest, RowidAlias) { - GenerateTypesTable(&db()); + GenerateTypesTable(&db_); // The id column is an alias for rowid, and its values get serialized as NULL. - ASSERT_TRUE(db().Execute( + ASSERT_TRUE(db_.Execute( "CREATE TABLE types2(id INTEGER PRIMARY KEY, rowtype TEXT, value)")); ASSERT_TRUE( - db().Execute("INSERT INTO types2(id, rowtype, value) " - "SELECT rowid, rowtype, value FROM types WHERE true")); - ASSERT_TRUE(db().Execute( + db_.Execute("INSERT INTO types2(id, rowtype, value) " + "SELECT rowid, rowtype, value FROM types WHERE true")); + ASSERT_TRUE(db_.Execute( "CREATE VIRTUAL TABLE temp.recover_types2 " "USING recover(types2, id ROWID NOT NULL, rowtype TEXT, value ANY)")); sql::Statement statement( - db().GetUniqueStatement("SELECT id, rowid, rowtype, value FROM types2")); + db_.GetUniqueStatement("SELECT id, rowid, rowtype, value FROM types2")); ASSERT_TRUE(statement.Step()); EXPECT_EQ(1, statement.ColumnInt(0)); @@ -819,7 +836,7 @@ TEST_F(RecoverModuleTest, RowidAlias) { } TEST_F(RecoverModuleTest, IntegerEncodings) { - ASSERT_TRUE(db().Execute("CREATE TABLE integers(value)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE integers(value)")); const std::vector<int64_t> values = { // Encoded directly in type info. @@ -857,7 +874,7 @@ TEST_F(RecoverModuleTest, IntegerEncodings) { -9223372036854775807, }; sql::Statement insert( - db().GetUniqueStatement("INSERT INTO integers VALUES(?)")); + db_.GetUniqueStatement("INSERT INTO integers VALUES(?)")); for (int64_t value : values) { insert.BindInt64(0, value); ASSERT_TRUE(insert.Run()); @@ -865,10 +882,10 @@ TEST_F(RecoverModuleTest, IntegerEncodings) { } ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_integers " - "USING recover(integers, value INTEGER)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_integers " + "USING recover(integers, value INTEGER)")); sql::Statement select( - db().GetUniqueStatement("SELECT rowid, value FROM recover_integers")); + db_.GetUniqueStatement("SELECT rowid, value FROM recover_integers")); for (size_t i = 0; i < values.size(); ++i) { ASSERT_TRUE(select.Step()) << "Was attemping to read " << values[i]; EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0)); @@ -967,38 +984,38 @@ TEST_F(RecoverModuleTest, VarintEncodings) { -0x8000000000000000, }; - ASSERT_TRUE(db().Execute("CREATE TABLE varints(value INTEGER PRIMARY KEY)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE varints(value INTEGER PRIMARY KEY)")); ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_varints " - "USING recover(varints, value ROWID)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_varints " + "USING recover(varints, value ROWID)")); for (int64_t value : values) { sql::Statement insert( - db().GetUniqueStatement("INSERT INTO varints VALUES(?)")); + db_.GetUniqueStatement("INSERT INTO varints VALUES(?)")); insert.BindInt64(0, value); ASSERT_TRUE(insert.Run()); sql::Statement select( - db().GetUniqueStatement("SELECT rowid, value FROM recover_varints")); + db_.GetUniqueStatement("SELECT rowid, value FROM recover_varints")); ASSERT_TRUE(select.Step()) << "Was attemping to read " << value; EXPECT_EQ(value, select.ColumnInt64(0)); EXPECT_EQ(value, select.ColumnInt64(1)); EXPECT_FALSE(select.Step()); - ASSERT_TRUE(db().Execute("DELETE FROM varints")); + ASSERT_TRUE(db_.Execute("DELETE FROM varints")); } } TEST_F(RecoverModuleTest, TextEncodings) { - ASSERT_TRUE(db().Execute("CREATE TABLE encodings(t TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE encodings(t TEXT)")); const std::vector<std::string> values = { - u8"Mjollnir", u8"Mjölnir", u8"Mjǫlnir", - u8"Mjölner", u8"Mjølner", u8"ハンマー", + "", "a", u8"ö", u8"Mjollnir", u8"Mjölnir", + u8"Mjǫlnir", u8"Mjölner", u8"Mjølner", u8"ハンマー", }; sql::Statement insert( - db().GetUniqueStatement("INSERT INTO encodings VALUES(?)")); + db_.GetUniqueStatement("INSERT INTO encodings VALUES(?)")); for (const std::string& value : values) { insert.BindString(0, value); ASSERT_TRUE(insert.Run()); @@ -1006,10 +1023,10 @@ TEST_F(RecoverModuleTest, TextEncodings) { } ASSERT_TRUE( - db().Execute("CREATE VIRTUAL TABLE temp.recover_encodings " - "USING recover(encodings, t TEXT)")); + db_.Execute("CREATE VIRTUAL TABLE temp.recover_encodings " + "USING recover(encodings, t TEXT)")); sql::Statement select( - db().GetUniqueStatement("SELECT rowid, t FROM recover_encodings")); + db_.GetUniqueStatement("SELECT rowid, t FROM recover_encodings")); for (size_t i = 0; i < values.size(); ++i) { ASSERT_TRUE(select.Step()); EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0)); @@ -1018,6 +1035,46 @@ TEST_F(RecoverModuleTest, TextEncodings) { EXPECT_FALSE(select.Step()); } +TEST_F(RecoverModuleTest, BlobEncodings) { + ASSERT_TRUE(db_.Execute("CREATE TABLE blob_encodings(t BLOB)")); + + const std::vector<std::vector<uint8_t>> values = { + {}, {0x00}, {0x01}, + {0x42}, {0xff}, {0x00, 0x00}, + {0x00, 0x01}, {0x00, 0xff}, {0x42, 0x43, 0x44, 0x45, 0x46}, + }; + + sql::Statement insert( + db_.GetUniqueStatement("INSERT INTO blob_encodings VALUES(?)")); + for (const std::vector<uint8_t>& value : values) { + // std::vector::data() returns nullptr for empty vectors. Unfortunately, + // sqlite3_bind_blob() always interprets null data as a NULL value. In this + // case, we really want to write an empty blob, so we need to pass non-null + // data. + const uint8_t* blob_data = + (value.size() > 0) ? value.data() : values[1].data(); + + insert.BindBlob(0, blob_data, value.size()); + ASSERT_TRUE(insert.Run()); + insert.Reset(/* clear_bound_vars= */ true); + } + + ASSERT_TRUE( + db_.Execute("CREATE VIRTUAL TABLE temp.recover_blob_encodings " + "USING recover(blob_encodings, t BLOB)")); + sql::Statement select( + db_.GetUniqueStatement("SELECT rowid, t FROM recover_blob_encodings")); + for (size_t i = 0; i < values.size(); ++i) { + ASSERT_TRUE(select.Step()); + EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0)); + + std::vector<uint8_t> column_value; + EXPECT_TRUE(select.ColumnBlobAsVector(1, &column_value)); + EXPECT_EQ(values[i], column_value); + } + EXPECT_FALSE(select.Step()); +} + namespace { std::string RandomString(int size) { @@ -1073,60 +1130,60 @@ constexpr int kOverflowOverhead = 4; } // namespace TEST_F(RecoverModuleTest, ValueWithoutOverflow) { - CheckLargeValueRecovery(&db(), db().page_size() - kRecordOverhead); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(2 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(2 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page and a leaf page"; } TEST_F(RecoverModuleTest, ValueWithOneByteOverflow) { - CheckLargeValueRecovery(&db(), db().page_size() - kRecordOverhead + 1); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + 1); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 1 overflow page"; } TEST_F(RecoverModuleTest, ValueWithOneOverflowPage) { CheckLargeValueRecovery( - &db(), db().page_size() - kRecordOverhead + db().page_size() / 2); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + &db_, db_.page_size() - kRecordOverhead + db_.page_size() / 2); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 1 overflow page"; } TEST_F(RecoverModuleTest, ValueWithOneFullOverflowPage) { - CheckLargeValueRecovery(&db(), db().page_size() - kRecordOverhead + - db().page_size() - kOverflowOverhead); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + + db_.page_size() - kOverflowOverhead); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 1 overflow page"; } TEST_F(RecoverModuleTest, ValueWithOneByteSecondOverflowPage) { - CheckLargeValueRecovery(&db(), db().page_size() - kRecordOverhead + - db().page_size() - kOverflowOverhead + 1); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + + db_.page_size() - kOverflowOverhead + 1); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 2 overflow pages"; } TEST_F(RecoverModuleTest, ValueWithTwoOverflowPages) { - CheckLargeValueRecovery(&db(), db().page_size() - kRecordOverhead + - db().page_size() - kOverflowOverhead + - db().page_size() / 2); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + + db_.page_size() - kOverflowOverhead + + db_.page_size() / 2); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 2 overflow pages"; } TEST_F(RecoverModuleTest, ValueWithTwoFullOverflowPages) { // This value is large enough that the varint encoding of its type ID takes up // 3 bytes, instead of 2. - CheckLargeValueRecovery(&db(), - db().page_size() - kRecordOverhead + - (db().page_size() - kOverflowOverhead) * 2 - 1); - int auto_vacuum_pages = HasEnabledAutoVacuum(&db()) ? 1 : 0; - ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db())) + CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + + (db_.page_size() - kOverflowOverhead) * 2 - + 1); + int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0; + ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_)) << "Database should have a root page, a leaf page, and 2 overflow pages"; } diff --git a/chromium/sql/recover_module/parsing.cc b/chromium/sql/recover_module/parsing.cc index 383ebe275b2..bbcf0b20b9c 100644 --- a/chromium/sql/recover_module/parsing.cc +++ b/chromium/sql/recover_module/parsing.cc @@ -10,10 +10,10 @@ #include "base/check.h" #include "base/notreached.h" -#include "base/optional.h" #include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "sql/recover_module/record.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace sql { namespace recover { @@ -62,7 +62,7 @@ constexpr base::StringPiece kStrictSql("STRICT"); constexpr base::StringPiece kNonNullSql1("NOT"); constexpr base::StringPiece kNonNullSql2("NULL"); -base::Optional<ModuleColumnType> ParseColumnType( +absl::optional<ModuleColumnType> ParseColumnType( base::StringPiece column_type_sql) { if (column_type_sql == kIntegerSql) return ModuleColumnType::kInteger; @@ -79,7 +79,7 @@ base::Optional<ModuleColumnType> ParseColumnType( if (column_type_sql == kAnySql) return ModuleColumnType::kAny; - return base::nullopt; + return absl::nullopt; } // Returns a view into a SQL string representing the column type. @@ -152,7 +152,7 @@ RecoveredColumnSpec ParseColumnSpec(const char* sqlite_arg) { base::StringPiece column_type_sql; std::tie(column_type_sql, sql) = SplitToken(sql); - base::Optional<ModuleColumnType> column_type = + absl::optional<ModuleColumnType> column_type = ParseColumnType(column_type_sql); if (!column_type.has_value()) { // Invalid column type. @@ -192,7 +192,7 @@ RecoveredColumnSpec ParseColumnSpec(const char* sqlite_arg) { result.is_non_null = true; } - result.name = column_name.as_string(); + result.name = std::string(column_name); return result; } @@ -212,7 +212,7 @@ TargetTableSpec ParseTableSpec(const char* sqlite_arg) { base::StringPiece db_name = sql.substr(0, separator_pos); base::StringPiece table_name = sql.substr(separator_pos + 1); - return TargetTableSpec{db_name.as_string(), table_name.as_string()}; + return TargetTableSpec{std::string(db_name), std::string(table_name)}; } } // namespace recover diff --git a/chromium/sql/recover_module/record.cc b/chromium/sql/recover_module/record.cc index 6c2be3fe91d..f85def5944f 100644 --- a/chromium/sql/recover_module/record.cc +++ b/chromium/sql/recover_module/record.cc @@ -246,7 +246,7 @@ bool RecordReader::ReadValue(int column_index, DCHECK(!header.has_inline_value); uint8_t* const value_bytes = new uint8_t[size]; - if (!payload_reader_->ReadPayload(offset, size, value_bytes)) { + if (size > 0 && !payload_reader_->ReadPayload(offset, size, value_bytes)) { delete[] value_bytes; return false; } @@ -313,4 +313,4 @@ int64_t RecordReader::InitializeHeaderBuffer() { } } // namespace recover -} // namespace sql
\ No newline at end of file +} // namespace sql diff --git a/chromium/sql/recover_module/table.cc b/chromium/sql/recover_module/table.cc index 65857e4368d..04f66ac77ee 100644 --- a/chromium/sql/recover_module/table.cc +++ b/chromium/sql/recover_module/table.cc @@ -20,12 +20,12 @@ namespace recover { // Returns a null optional if the operation fails in any way. The failure is // most likely due to an incorrect table spec (missing attachment or table). // Corrupted SQLite metadata can cause failures here. -base::Optional<int> GetTableRootPageId(sqlite3* sqlite_db, +absl::optional<int> GetTableRootPageId(sqlite3* sqlite_db, const TargetTableSpec& table) { if (table.table_name == "sqlite_master") { // The sqlite_master table is always rooted at the first page. // SQLite page IDs use 1-based indexing. - return base::Optional<int64_t>(1); + return absl::optional<int64_t>(1); } std::string select_sql = @@ -36,7 +36,7 @@ base::Optional<int> GetTableRootPageId(sqlite3* sqlite_db, SQLITE_PREPARE_NO_VTAB, &sqlite_statement, nullptr) != SQLITE_OK) { // The sqlite_master table is missing or its schema is corrupted. - return base::nullopt; + return absl::nullopt; } if (sqlite3_bind_text(sqlite_statement, 1, table.table_name.c_str(), @@ -44,13 +44,13 @@ base::Optional<int> GetTableRootPageId(sqlite3* sqlite_db, SQLITE_STATIC) != SQLITE_OK) { // Binding the table name failed. This shouldn't happen. sqlite3_finalize(sqlite_statement); - return base::nullopt; + return absl::nullopt; } if (sqlite3_step(sqlite_statement) != SQLITE_ROW) { // The database attachment point or table does not exist. sqlite3_finalize(sqlite_statement); - return base::nullopt; + return absl::nullopt; } int64_t root_page = sqlite3_column_int64(sqlite_statement, 0); @@ -58,13 +58,13 @@ base::Optional<int> GetTableRootPageId(sqlite3* sqlite_db, if (!DatabasePageReader::IsValidPageId(root_page)) { // Database corruption. - return base::nullopt; + return absl::nullopt; } static_assert( DatabasePageReader::kMaxPageId <= std::numeric_limits<int>::max(), "Converting the page ID to int may overflow"); - return base::make_optional(static_cast<int>(root_page)); + return absl::make_optional(static_cast<int>(root_page)); } // Returns (SQLite status, a SQLite database's page size). @@ -125,7 +125,7 @@ std::pair<int, std::unique_ptr<VirtualTable>> VirtualTable::Create( std::vector<RecoveredColumnSpec> column_specs) { DCHECK(backing_table_spec.IsValid()); - base::Optional<int64_t> backing_table_root_page_id = + absl::optional<int64_t> backing_table_root_page_id = GetTableRootPageId(sqlite_db, backing_table_spec); if (!backing_table_root_page_id.has_value()) { // Either the backing table specification is incorrect, or the database diff --git a/chromium/sql/recover_module/table.h b/chromium/sql/recover_module/table.h index 409d12cf8c2..95d6f9ea79b 100644 --- a/chromium/sql/recover_module/table.h +++ b/chromium/sql/recover_module/table.h @@ -12,8 +12,8 @@ #include <vector> #include "base/check_op.h" -#include "base/optional.h" #include "sql/recover_module/parsing.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/sqlite/sqlite3.h" namespace sql { diff --git a/chromium/sql/recovery_unittest.cc b/chromium/sql/recovery_unittest.cc index afd386574f3..f40290757a0 100644 --- a/chromium/sql/recovery_unittest.cc +++ b/chromium/sql/recovery_unittest.cc @@ -22,11 +22,12 @@ #include "sql/statement.h" #include "sql/test/paths.h" #include "sql/test/scoped_error_expecter.h" -#include "sql/test/sql_test_base.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" +namespace sql { + namespace { using sql::test::ExecuteWithResult; @@ -36,81 +37,104 @@ using sql::test::ExecuteWithResults; // schema. For tables or indices, this will contain the sql command // to create the table or index. For certain automatic SQLite // structures with no sql, the name is used. -std::string GetSchema(sql::Database* db) { +std::string GetSchema(Database* db) { static const char kSql[] = "SELECT COALESCE(sql, name) FROM sqlite_master ORDER BY 1"; return ExecuteWithResults(db, kSql, "|", "\n"); } -using SQLRecoveryTest = sql::SQLTestBase; +class SQLRecoveryTest : public testing::Test { + public: + ~SQLRecoveryTest() override = default; + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_path_ = temp_dir_.GetPath().AppendASCII("recovery_test.sqlite"); + ASSERT_TRUE(db_.Open(db_path_)); + } + + bool Reopen() { + db_.Close(); + return db_.Open(db_path_); + } -// Baseline sql::Recovery test covering the different ways to dispose of the -// scoped pointer received from sql::Recovery::Begin(). + bool OverwriteDatabaseHeader() { + base::File file(db_path_, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + static constexpr char kText[] = "Now is the winter of our discontent."; + constexpr int kTextBytes = sizeof(kText) - 1; + return file.Write(0, kText, kTextBytes) == kTextBytes; + } + + protected: + base::ScopedTempDir temp_dir_; + base::FilePath db_path_; + Database db_; +}; + +// Baseline Recovery test covering the different ways to dispose of the +// scoped pointer received from Recovery::Begin(). TEST_F(SQLRecoveryTest, RecoverBasic) { static const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; static const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')"; static const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kInsertSql)); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute(kInsertSql)); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); // If the Recovery handle goes out of scope without being // Recovered(), the database is razed. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); } - EXPECT_FALSE(db().is_open()); + EXPECT_FALSE(db_.is_open()); ASSERT_TRUE(Reopen()); - EXPECT_TRUE(db().is_open()); - ASSERT_EQ("", GetSchema(&db())); + EXPECT_TRUE(db_.is_open()); + ASSERT_EQ("", GetSchema(&db_)); // Recreate the database. - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kInsertSql)); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute(kInsertSql)); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); // Unrecoverable() also razes. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); - sql::Recovery::Unrecoverable(std::move(recovery)); + Recovery::Unrecoverable(std::move(recovery)); - // TODO(shess): Test that calls to recover.db() start failing. + // TODO(shess): Test that calls to recover.db_ start failing. } - EXPECT_FALSE(db().is_open()); + EXPECT_FALSE(db_.is_open()); ASSERT_TRUE(Reopen()); - EXPECT_TRUE(db().is_open()); - ASSERT_EQ("", GetSchema(&db())); + EXPECT_TRUE(db_.is_open()); + ASSERT_EQ("", GetSchema(&db_)); // Attempting to recover a previously-recovered handle fails early. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); recovery.reset(); - recovery = sql::Recovery::Begin(&db(), db_path()); + recovery = Recovery::Begin(&db_, db_path_); ASSERT_FALSE(recovery.get()); } ASSERT_TRUE(Reopen()); // Recreate the database. - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute(kInsertSql)); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute(kInsertSql)); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); // Unrecovered table to distinguish from recovered database. - ASSERT_TRUE(db().Execute("CREATE TABLE y (c INTEGER)")); - ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db())); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c INTEGER)")); + ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db_)); // Recovered() replaces the original with the "recovered" version. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); // Create the new version of the table. @@ -120,50 +144,48 @@ TEST_F(SQLRecoveryTest, RecoverBasic) { ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); // Successfully recovered. - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } - EXPECT_FALSE(db().is_open()); + EXPECT_FALSE(db_.is_open()); ASSERT_TRUE(Reopen()); - EXPECT_TRUE(db().is_open()); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + EXPECT_TRUE(db_.is_open()); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); const char* kXSql = "SELECT * FROM x ORDER BY 1"; - ASSERT_EQ("That was a test", ExecuteWithResult(&db(), kXSql)); + ASSERT_EQ("That was a test", ExecuteWithResult(&db_, kXSql)); // Reset the database contents. - ASSERT_TRUE(db().Execute("DELETE FROM x")); - ASSERT_TRUE(db().Execute(kInsertSql)); + ASSERT_TRUE(db_.Execute("DELETE FROM x")); + ASSERT_TRUE(db_.Execute(kInsertSql)); // Rollback() discards recovery progress and leaves the database as it was. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); - sql::Recovery::Rollback(std::move(recovery)); + Recovery::Rollback(std::move(recovery)); } - EXPECT_FALSE(db().is_open()); + EXPECT_FALSE(db_.is_open()); ASSERT_TRUE(Reopen()); - EXPECT_TRUE(db().is_open()); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + EXPECT_TRUE(db_.is_open()); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); - ASSERT_EQ("This is a test", ExecuteWithResult(&db(), kXSql)); + ASSERT_EQ("This is a test", ExecuteWithResult(&db_, kXSql)); } -// Test operation of the virtual table used by sql::Recovery. +// Test operation of the virtual table used by Recovery. TEST_F(SQLRecoveryTest, VirtualTable) { static const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('That was a test')")); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('That was a test')")); // Successfully recover the database. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); // Tables to recover original DB, now at [corrupt]. static const char kRecoveryCreateSql[] = @@ -182,32 +204,32 @@ TEST_F(SQLRecoveryTest, VirtualTable) { ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql)); // Successfully recovered. - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); + ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_)); static const char* kXSql = "SELECT * FROM x ORDER BY 1"; ASSERT_EQ("That was a test\nThis is a test", - ExecuteWithResults(&db(), kXSql, "|", "\n")); + ExecuteWithResults(&db_, kXSql, "|", "\n")); } -void RecoveryCallback(sql::Database* db, +void RecoveryCallback(Database* db, const base::FilePath& db_path, const char* create_table, const char* create_index, int* record_error, int error, - sql::Statement* stmt) { + Statement* stmt) { *record_error = error; // Clear the error callback to prevent reentrancy. db->reset_error_callback(); - std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); + std::unique_ptr<Recovery> recovery = Recovery::Begin(db, db_path); ASSERT_TRUE(recovery.get()); ASSERT_TRUE(recovery->db()->Execute(create_table)); @@ -216,7 +238,7 @@ void RecoveryCallback(sql::Database* db, size_t rows = 0; ASSERT_TRUE(recovery->AutoRecoverTable("x", &rows)); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Build a database, corrupt it by making an index reference to @@ -224,15 +246,15 @@ void RecoveryCallback(sql::Database* db, TEST_F(SQLRecoveryTest, RecoverCorruptIndex) { static const char kCreateTable[] = "CREATE TABLE x (id INTEGER, v INTEGER)"; static const char kCreateIndex[] = "CREATE UNIQUE INDEX x_id ON x (id)"; - ASSERT_TRUE(db().Execute(kCreateTable)); - ASSERT_TRUE(db().Execute(kCreateIndex)); + ASSERT_TRUE(db_.Execute(kCreateTable)); + ASSERT_TRUE(db_.Execute(kCreateIndex)); // Insert a bit of data. { - ASSERT_TRUE(db().BeginTransaction()); + ASSERT_TRUE(db_.BeginTransaction()); static const char kInsertSql[] = "INSERT INTO x (id, v) VALUES (?, ?)"; - sql::Statement s(db().GetUniqueStatement(kInsertSql)); + Statement s(db_.GetUniqueStatement(kInsertSql)); for (int i = 0; i < 10; ++i) { s.Reset(true); s.BindInt(0, i); @@ -241,42 +263,42 @@ TEST_F(SQLRecoveryTest, RecoverCorruptIndex) { EXPECT_TRUE(s.Succeeded()); } - ASSERT_TRUE(db().CommitTransaction()); + ASSERT_TRUE(db_.CommitTransaction()); } - db().Close(); + db_.Close(); // Delete a row from the table, while leaving the index entry which // references it. static const char kDeleteSql[] = "DELETE FROM x WHERE id = 0"; - ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path(), "x_id", kDeleteSql)); + ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path_, "x_id", kDeleteSql)); ASSERT_TRUE(Reopen()); int error = SQLITE_OK; - db().set_error_callback(base::BindRepeating( - &RecoveryCallback, &db(), db_path(), kCreateTable, kCreateIndex, &error)); + db_.set_error_callback(base::BindRepeating( + &RecoveryCallback, &db_, db_path_, kCreateTable, kCreateIndex, &error)); // This works before the callback is called. static const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master"; - EXPECT_TRUE(db().IsSQLValid(kTrivialSql)); + EXPECT_TRUE(db_.IsSQLValid(kTrivialSql)); // TODO(shess): Could this be delete? Anything which fails should work. static const char kSelectSql[] = "SELECT v FROM x WHERE id = 0"; - ASSERT_FALSE(db().Execute(kSelectSql)); + ASSERT_FALSE(db_.Execute(kSelectSql)); EXPECT_EQ(SQLITE_CORRUPT, error); // Database handle has been poisoned. - EXPECT_FALSE(db().IsSQLValid(kTrivialSql)); + EXPECT_FALSE(db_.IsSQLValid(kTrivialSql)); ASSERT_TRUE(Reopen()); // The recovered table should reflect the deletion. static const char kSelectAllSql[] = "SELECT v FROM x ORDER BY id"; EXPECT_EQ("1,2,3,4,5,6,7,8,9", - ExecuteWithResults(&db(), kSelectAllSql, "|", ",")); + ExecuteWithResults(&db_, kSelectAllSql, "|", ",")); // The failing statement should now succeed, with no results. - EXPECT_EQ("", ExecuteWithResults(&db(), kSelectSql, "|", ",")); + EXPECT_EQ("", ExecuteWithResults(&db_, kSelectSql, "|", ",")); } // Build a database, corrupt it by making a table contain a row not @@ -284,15 +306,15 @@ TEST_F(SQLRecoveryTest, RecoverCorruptIndex) { TEST_F(SQLRecoveryTest, RecoverCorruptTable) { static const char kCreateTable[] = "CREATE TABLE x (id INTEGER, v INTEGER)"; static const char kCreateIndex[] = "CREATE UNIQUE INDEX x_id ON x (id)"; - ASSERT_TRUE(db().Execute(kCreateTable)); - ASSERT_TRUE(db().Execute(kCreateIndex)); + ASSERT_TRUE(db_.Execute(kCreateTable)); + ASSERT_TRUE(db_.Execute(kCreateIndex)); // Insert a bit of data. { - ASSERT_TRUE(db().BeginTransaction()); + ASSERT_TRUE(db_.BeginTransaction()); static const char kInsertSql[] = "INSERT INTO x (id, v) VALUES (?, ?)"; - sql::Statement s(db().GetUniqueStatement(kInsertSql)); + Statement s(db_.GetUniqueStatement(kInsertSql)); for (int i = 0; i < 10; ++i) { s.Reset(true); s.BindInt(0, i); @@ -301,62 +323,62 @@ TEST_F(SQLRecoveryTest, RecoverCorruptTable) { EXPECT_TRUE(s.Succeeded()); } - ASSERT_TRUE(db().CommitTransaction()); + ASSERT_TRUE(db_.CommitTransaction()); } - db().Close(); + db_.Close(); // Delete a row from the index while leaving a table entry. static const char kDeleteSql[] = "DELETE FROM x WHERE id = 0"; - ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path(), "x", kDeleteSql)); + ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path_, "x", kDeleteSql)); ASSERT_TRUE(Reopen()); int error = SQLITE_OK; - db().set_error_callback(base::BindRepeating( - &RecoveryCallback, &db(), db_path(), kCreateTable, kCreateIndex, &error)); + db_.set_error_callback(base::BindRepeating( + &RecoveryCallback, &db_, db_path_, kCreateTable, kCreateIndex, &error)); // Index shows one less than originally inserted. static const char kCountSql[] = "SELECT COUNT (*) FROM x"; - EXPECT_EQ("9", ExecuteWithResult(&db(), kCountSql)); + EXPECT_EQ("9", ExecuteWithResult(&db_, kCountSql)); // A full table scan shows all of the original data. Using column [v] to // force use of the table rather than the index. static const char kDistinctSql[] = "SELECT DISTINCT COUNT (v) FROM x"; - EXPECT_EQ("10", ExecuteWithResult(&db(), kDistinctSql)); + EXPECT_EQ("10", ExecuteWithResult(&db_, kDistinctSql)); // Insert id 0 again. Since it is not in the index, the insert // succeeds, but results in a duplicate value in the table. static const char kInsertSql[] = "INSERT INTO x (id, v) VALUES (0, 100)"; - ASSERT_TRUE(db().Execute(kInsertSql)); + ASSERT_TRUE(db_.Execute(kInsertSql)); // Duplication is visible. - EXPECT_EQ("10", ExecuteWithResult(&db(), kCountSql)); - EXPECT_EQ("11", ExecuteWithResult(&db(), kDistinctSql)); + EXPECT_EQ("10", ExecuteWithResult(&db_, kCountSql)); + EXPECT_EQ("11", ExecuteWithResult(&db_, kDistinctSql)); // This works before the callback is called. static const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master"; - EXPECT_TRUE(db().IsSQLValid(kTrivialSql)); + EXPECT_TRUE(db_.IsSQLValid(kTrivialSql)); // TODO(shess): Figure out a statement which causes SQLite to notice the // corruption. SELECT doesn't see errors because missing index values aren't // visible. UPDATE or DELETE against v=0 don't see errors, even though the // index item is missing. I suspect SQLite only deletes the key in these // cases, but doesn't verify that one or more keys were deleted. - ASSERT_FALSE(db().Execute("INSERT INTO x (id, v) VALUES (0, 101)")); + ASSERT_FALSE(db_.Execute("INSERT INTO x (id, v) VALUES (0, 101)")); EXPECT_EQ(SQLITE_CONSTRAINT_UNIQUE, error); // Database handle has been poisoned. - EXPECT_FALSE(db().IsSQLValid(kTrivialSql)); + EXPECT_FALSE(db_.IsSQLValid(kTrivialSql)); ASSERT_TRUE(Reopen()); // The recovered table has consistency between the index and the table. - EXPECT_EQ("10", ExecuteWithResult(&db(), kCountSql)); - EXPECT_EQ("10", ExecuteWithResult(&db(), kDistinctSql)); + EXPECT_EQ("10", ExecuteWithResult(&db_, kCountSql)); + EXPECT_EQ("10", ExecuteWithResult(&db_, kDistinctSql)); // Only one of the values is retained. static const char kSelectSql[] = "SELECT v FROM x WHERE id = 0"; - const std::string results = ExecuteWithResult(&db(), kSelectSql); + const std::string results = ExecuteWithResult(&db_, kSelectSql); EXPECT_TRUE(results=="100" || results=="0") << "Actual results: " << results; } @@ -365,45 +387,42 @@ TEST_F(SQLRecoveryTest, Meta) { const int kCompatibleVersion = 2; { - sql::MetaTable meta; - EXPECT_TRUE(meta.Init(&db(), kVersion, kCompatibleVersion)); + MetaTable meta; + EXPECT_TRUE(meta.Init(&db_, kVersion, kCompatibleVersion)); EXPECT_EQ(kVersion, meta.GetVersionNumber()); } // Test expected case where everything works. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); EXPECT_TRUE(recovery->SetupMeta()); int version = 0; EXPECT_TRUE(recovery->GetMetaVersionNumber(&version)); EXPECT_EQ(kVersion, version); - sql::Recovery::Rollback(std::move(recovery)); + Recovery::Rollback(std::move(recovery)); } ASSERT_TRUE(Reopen()); // Handle was poisoned. // Test version row missing. - EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); + EXPECT_TRUE(db_.Execute("DELETE FROM meta WHERE key = 'version'")); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); EXPECT_TRUE(recovery->SetupMeta()); int version = 0; EXPECT_FALSE(recovery->GetMetaVersionNumber(&version)); EXPECT_EQ(0, version); - sql::Recovery::Rollback(std::move(recovery)); + Recovery::Rollback(std::move(recovery)); } ASSERT_TRUE(Reopen()); // Handle was poisoned. // Test meta table missing. - EXPECT_TRUE(db().Execute("DROP TABLE meta")); + EXPECT_TRUE(db_.Execute("DROP TABLE meta")); { sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); // From virtual table. - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); EXPECT_FALSE(recovery->SetupMeta()); ASSERT_TRUE(expecter.SawExpectedErrors()); } @@ -414,23 +433,22 @@ TEST_F(SQLRecoveryTest, AutoRecoverTable) { // BIGINT and VARCHAR to test type affinity. static const char kCreateSql[] = "CREATE TABLE x (id BIGINT, t TEXT, v VARCHAR)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (11, 'This is', 'a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, 'That was', 'a test')")); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (11, 'This is', 'a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5, 'That was', 'a test')")); // Save aside a copy of the original schema and data. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; - const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); + const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n")); // Create a lame-duck table which will not be propagated by recovery to // detect that the recovery code actually ran. - ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); - ASSERT_NE(orig_schema, GetSchema(&db())); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)")); + ASSERT_NE(orig_schema, GetSchema(&db_)); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); // Save a copy of the temp db's schema before recovering the table. @@ -447,26 +465,25 @@ TEST_F(SQLRecoveryTest, AutoRecoverTable) { EXPECT_EQ(temp_schema, ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(orig_schema, GetSchema(&db())); - ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ(orig_schema, GetSchema(&db_)); + ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n")); // Recovery fails if the target table doesn't exist. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); // TODO(shess): Should this failure implicitly lead to Raze()? size_t rows = 0; EXPECT_FALSE(recovery->AutoRecoverTable("y", &rows)); - sql::Recovery::Unrecoverable(std::move(recovery)); + Recovery::Unrecoverable(std::move(recovery)); } } @@ -474,30 +491,30 @@ TEST_F(SQLRecoveryTest, AutoRecoverTable) { // virtual table reads directly from the database, so DEFAULT is not // interpretted at that level. TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { - ASSERT_TRUE(db().Execute("CREATE TABLE x (id INTEGER)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE x (id INTEGER)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (15)")); // ALTER effectively leaves the new columns NULL in the first two // rows. The row with 17 will get the default injected at insert // time, while the row with 42 will get the actual value provided. // Embedded "'" to make sure default-handling continues to be quoted // correctly. - ASSERT_TRUE(db().Execute("ALTER TABLE x ADD COLUMN t TEXT DEFAULT 'a''a'")); - ASSERT_TRUE(db().Execute("ALTER TABLE x ADD COLUMN b BLOB DEFAULT x'AA55'")); - ASSERT_TRUE(db().Execute("ALTER TABLE x ADD COLUMN i INT DEFAULT 93")); - ASSERT_TRUE(db().Execute("INSERT INTO x (id) VALUES (17)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (42, 'b', x'1234', 12)")); + ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN t TEXT DEFAULT 'a''a'")); + ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN b BLOB DEFAULT x'AA55'")); + ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN i INT DEFAULT 93")); + ASSERT_TRUE(db_.Execute("INSERT INTO x (id) VALUES (17)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (42, 'b', x'1234', 12)")); // Save aside a copy of the original schema and data. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; - const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); + const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n")); // Create a lame-duck table which will not be propagated by recovery to // detect that the recovery code actually ran. - ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); - ASSERT_NE(orig_schema, GetSchema(&db())); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)")); + ASSERT_NE(orig_schema, GetSchema(&db_)); // Mechanically adjust the stored schema and data to allow detecting // where the default value is coming from. The target table is just @@ -516,8 +533,7 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { } { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); // Different default to detect which table provides the default. ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); @@ -525,14 +541,14 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); EXPECT_EQ(4u, rows); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(final_schema, GetSchema(&db())); - ASSERT_EQ(final_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ(final_schema, GetSchema(&db_)); + ASSERT_EQ(final_data, ExecuteWithResults(&db_, kXSql, "|", "\n")); } // Test that rows with NULL in a NOT NULL column are filtered @@ -544,34 +560,33 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableNullFilter) { static const char kFinalSchema[] = "CREATE TABLE x (id INTEGER, t TEXT NOT NULL)"; - ASSERT_TRUE(db().Execute(kOrigSchema)); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, NULL)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15, 'this is a test')")); + ASSERT_TRUE(db_.Execute(kOrigSchema)); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5, NULL)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (15, 'this is a test')")); // Create a lame-duck table which will not be propagated by recovery to // detect that the recovery code actually ran. - ASSERT_EQ(kOrigSchema, GetSchema(&db())); - ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); - ASSERT_NE(kOrigSchema, GetSchema(&db())); + ASSERT_EQ(kOrigSchema, GetSchema(&db_)); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)")); + ASSERT_NE(kOrigSchema, GetSchema(&db_)); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); size_t rows = 0; EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); EXPECT_EQ(1u, rows); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // The schema should be the same, but only one row of data should // have been recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(kFinalSchema, GetSchema(&db())); + ASSERT_EQ(kFinalSchema, GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; - ASSERT_EQ("15|this is a test", ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ("15|this is a test", ExecuteWithResults(&db_, kXSql, "|", "\n")); } // Test AutoRecoverTable with a ROWID alias. @@ -580,37 +595,36 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableWithRowid) { // put it later. static const char kCreateSql[] = "CREATE TABLE x (t TEXT, id INTEGER PRIMARY KEY NOT NULL)"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test', NULL)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('That was a test', NULL)")); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test', NULL)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('That was a test', NULL)")); // Save aside a copy of the original schema and data. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; - const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); + const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n")); // Create a lame-duck table which will not be propagated by recovery to // detect that the recovery code actually ran. - ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); - ASSERT_NE(orig_schema, GetSchema(&db())); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)")); + ASSERT_NE(orig_schema, GetSchema(&db_)); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); size_t rows = 0; EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); EXPECT_EQ(2u, rows); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(orig_schema, GetSchema(&db())); - ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ(orig_schema, GetSchema(&db_)); + ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n")); } // Test that a compound primary key doesn't fire the ROWID code. @@ -622,41 +636,40 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableWithCompoundKey) { "t TEXT," "PRIMARY KEY (id, id2)" ")"; - ASSERT_TRUE(db().Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute(kCreateSql)); // NOTE(shess): Do not accidentally use [id] 1, 2, 3, as those will // be the ROWID values. - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (1, 'a', 'This is a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (1, 'b', 'That was a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (2, 'a', 'Another test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'a', 'This is a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'b', 'That was a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (2, 'a', 'Another test')")); // Save aside a copy of the original schema and data. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; - const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); + const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n")); // Create a lame-duck table which will not be propagated by recovery to // detect that the recovery code actually ran. - ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); - ASSERT_NE(orig_schema, GetSchema(&db())); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)")); + ASSERT_NE(orig_schema, GetSchema(&db_)); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); size_t rows = 0; EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); EXPECT_EQ(3u, rows); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(orig_schema, GetSchema(&db())); - ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ(orig_schema, GetSchema(&db_)); + ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n")); } // Test recovering from a table with fewer columns than the target. @@ -665,46 +678,45 @@ TEST_F(SQLRecoveryTest, AutoRecoverTableMissingColumns) { "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; static const char kAlterSql[] = "ALTER TABLE x ADD COLUMN t1 TEXT DEFAULT 't'"; - ASSERT_TRUE(db().Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (1, 'This is')")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (2, 'That was')")); + ASSERT_TRUE(db_.Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'This is')")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (2, 'That was')")); // Generate the expected info by faking a table to match what recovery will // create. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; std::string expected_schema; std::string expected_data; { - ASSERT_TRUE(db().BeginTransaction()); - ASSERT_TRUE(db().Execute(kAlterSql)); + ASSERT_TRUE(db_.BeginTransaction()); + ASSERT_TRUE(db_.Execute(kAlterSql)); - expected_schema = GetSchema(&db()); - expected_data = ExecuteWithResults(&db(), kXSql, "|", "\n"); + expected_schema = GetSchema(&db_); + expected_data = ExecuteWithResults(&db_, kXSql, "|", "\n"); - db().RollbackTransaction(); + db_.RollbackTransaction(); } // Following tests are pointless if the rollback didn't work. - ASSERT_EQ(orig_schema, GetSchema(&db())); + ASSERT_EQ(orig_schema, GetSchema(&db_)); // Recover the previous version of the table into the altered version. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); ASSERT_TRUE(recovery->db()->Execute(kAlterSql)); size_t rows = 0; EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); EXPECT_EQ(2u, rows); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(expected_schema, GetSchema(&db())); - ASSERT_EQ(expected_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_EQ(expected_schema, GetSchema(&db_)); + ASSERT_EQ(expected_data, ExecuteWithResults(&db_, kXSql, "|", "\n")); } // Recover a golden file where an interior page has been manually modified so @@ -714,13 +726,12 @@ TEST_F(SQLRecoveryTest, Bug387868) { base::FilePath golden_path; ASSERT_TRUE(base::PathService::Get(sql::test::DIR_TEST_DATA, &golden_path)); golden_path = golden_path.AppendASCII("recovery_387868"); - db().Close(); - ASSERT_TRUE(base::CopyFile(golden_path, db_path())); + db_.Close(); + ASSERT_TRUE(base::CopyFile(golden_path, db_path_)); ASSERT_TRUE(Reopen()); { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); // Create the new version of the table. @@ -733,96 +744,95 @@ TEST_F(SQLRecoveryTest, Bug387868) { EXPECT_EQ(43u, rows); // Successfully recovered. - EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + EXPECT_TRUE(Recovery::Recovered(std::move(recovery))); } } // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery // database doesn't accidentally enable it. TEST_F(SQLRecoveryTest, NoMmap) { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_TRUE(recovery.get()); // In the current implementation, the PRAGMA successfully runs with no result // rows. Running with a single result of |0| is also acceptable. - sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); + Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); } TEST_F(SQLRecoveryTest, RecoverDatabase) { // As a side effect, AUTOINCREMENT creates the sqlite_sequence table for // RecoverDatabase() to handle. - ASSERT_TRUE(db().Execute( + ASSERT_TRUE(db_.Execute( "CREATE TABLE x (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT)")); - EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('turtle')")); - EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('truck')")); - EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('trailer')")); + EXPECT_TRUE(db_.Execute("INSERT INTO x (v) VALUES ('turtle')")); + EXPECT_TRUE(db_.Execute("INSERT INTO x (v) VALUES ('truck')")); + EXPECT_TRUE(db_.Execute("INSERT INTO x (v) VALUES ('trailer')")); // This table needs index and a unique index to work. - ASSERT_TRUE(db().Execute("CREATE TABLE y (name TEXT, v TEXT)")); - ASSERT_TRUE(db().Execute("CREATE UNIQUE INDEX y_name ON y(name)")); - ASSERT_TRUE(db().Execute("CREATE INDEX y_v ON y(v)")); - EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('jim', 'telephone')")); - EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('bob', 'truck')")); - EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('dean', 'trailer')")); + ASSERT_TRUE(db_.Execute("CREATE TABLE y (name TEXT, v TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE UNIQUE INDEX y_name ON y(name)")); + ASSERT_TRUE(db_.Execute("CREATE INDEX y_v ON y(v)")); + EXPECT_TRUE(db_.Execute("INSERT INTO y VALUES ('jim', 'telephone')")); + EXPECT_TRUE(db_.Execute("INSERT INTO y VALUES ('bob', 'truck')")); + EXPECT_TRUE(db_.Execute("INSERT INTO y VALUES ('dean', 'trailer')")); // View which is the intersection of [x.v] and [y.v]. - ASSERT_TRUE(db().Execute( - "CREATE VIEW v AS SELECT x.v FROM x, y WHERE x.v = y.v")); + ASSERT_TRUE( + db_.Execute("CREATE VIEW v AS SELECT x.v FROM x, y WHERE x.v = y.v")); // When an element is deleted from [x], trigger a delete on [y]. Between the // BEGIN and END, [old] stands for the deleted rows from [x]. - ASSERT_TRUE(db().Execute("CREATE TRIGGER t AFTER DELETE ON x " - "BEGIN DELETE FROM y WHERE y.v = old.v; END")); + ASSERT_TRUE( + db_.Execute("CREATE TRIGGER t AFTER DELETE ON x " + "BEGIN DELETE FROM y WHERE y.v = old.v; END")); // Save aside a copy of the original schema, verifying that it has the created // items plus the sqlite_sequence table. - const std::string orig_schema(GetSchema(&db())); + const std::string orig_schema(GetSchema(&db_)); ASSERT_EQ(6, std::count(orig_schema.begin(), orig_schema.end(), '\n')); static const char kXSql[] = "SELECT * FROM x ORDER BY 1"; static const char kYSql[] = "SELECT * FROM y ORDER BY 1"; static const char kVSql[] = "SELECT * FROM v ORDER BY 1"; EXPECT_EQ("1|turtle\n2|truck\n3|trailer", - ExecuteWithResults(&db(), kXSql, "|", "\n")); + ExecuteWithResults(&db_, kXSql, "|", "\n")); EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone", - ExecuteWithResults(&db(), kYSql, "|", "\n")); - EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db(), kVSql, "|", "\n")); + ExecuteWithResults(&db_, kYSql, "|", "\n")); + EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db_, kVSql, "|", "\n")); // Database handle is valid before recovery, poisoned after. static const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master"; - EXPECT_TRUE(db().IsSQLValid(kTrivialSql)); - sql::Recovery::RecoverDatabase(&db(), db_path()); - EXPECT_FALSE(db().IsSQLValid(kTrivialSql)); + EXPECT_TRUE(db_.IsSQLValid(kTrivialSql)); + Recovery::RecoverDatabase(&db_, db_path_); + EXPECT_FALSE(db_.IsSQLValid(kTrivialSql)); // Since the database was not corrupt, the entire schema and all // data should be recovered. ASSERT_TRUE(Reopen()); - ASSERT_EQ(orig_schema, GetSchema(&db())); + ASSERT_EQ(orig_schema, GetSchema(&db_)); EXPECT_EQ("1|turtle\n2|truck\n3|trailer", - ExecuteWithResults(&db(), kXSql, "|", "\n")); + ExecuteWithResults(&db_, kXSql, "|", "\n")); EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone", - ExecuteWithResults(&db(), kYSql, "|", "\n")); - EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db(), kVSql, "|", "\n")); + ExecuteWithResults(&db_, kYSql, "|", "\n")); + EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db_, kVSql, "|", "\n")); // Test that the trigger works. - ASSERT_TRUE(db().Execute("DELETE FROM x WHERE v = 'truck'")); - EXPECT_EQ("1|turtle\n3|trailer", - ExecuteWithResults(&db(), kXSql, "|", "\n")); + ASSERT_TRUE(db_.Execute("DELETE FROM x WHERE v = 'truck'")); + EXPECT_EQ("1|turtle\n3|trailer", ExecuteWithResults(&db_, kXSql, "|", "\n")); EXPECT_EQ("dean|trailer\njim|telephone", - ExecuteWithResults(&db(), kYSql, "|", "\n")); - EXPECT_EQ("trailer", ExecuteWithResults(&db(), kVSql, "|", "\n")); + ExecuteWithResults(&db_, kYSql, "|", "\n")); + EXPECT_EQ("trailer", ExecuteWithResults(&db_, kVSql, "|", "\n")); } // When RecoverDatabase() encounters SQLITE_NOTADB, the database is deleted. TEST_F(SQLRecoveryTest, RecoverDatabaseDelete) { // Create a valid database, then write junk over the header. This should lead // to SQLITE_NOTADB, which will cause ATTACH to fail. - ASSERT_TRUE(db().Execute("CREATE TABLE x (t TEXT)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test')")); - db().Close(); - WriteJunkToDatabase(SQLTestBase::TYPE_OVERWRITE); + ASSERT_TRUE(db_.Execute("CREATE TABLE x (t TEXT)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')")); + db_.Close(); + ASSERT_TRUE(OverwriteDatabaseHeader()); { sql::test::ScopedErrorExpecter expecter; @@ -832,74 +842,74 @@ TEST_F(SQLRecoveryTest, RecoverDatabaseDelete) { ASSERT_TRUE(Reopen()); // This should "recover" the database by making it valid, but empty. - sql::Recovery::RecoverDatabase(&db(), db_path()); + Recovery::RecoverDatabase(&db_, db_path_); ASSERT_TRUE(expecter.SawExpectedErrors()); } // Recovery poisoned the handle, must re-open. - db().Close(); + db_.Close(); ASSERT_TRUE(Reopen()); - EXPECT_EQ("", GetSchema(&db())); + EXPECT_EQ("", GetSchema(&db_)); } // Allow callers to validate the database between recovery and commit. TEST_F(SQLRecoveryTest, BeginRecoverDatabase) { // Create a table with a broken index. - ASSERT_TRUE(db().Execute("CREATE TABLE t (id INTEGER PRIMARY KEY, c TEXT)")); - ASSERT_TRUE(db().Execute("CREATE UNIQUE INDEX t_id ON t (id)")); - ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (1, 'hello world')")); - ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (2, 'testing')")); - ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (3, 'nope')")); + ASSERT_TRUE(db_.Execute("CREATE TABLE t (id INTEGER PRIMARY KEY, c TEXT)")); + ASSERT_TRUE(db_.Execute("CREATE UNIQUE INDEX t_id ON t (id)")); + ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (1, 'hello world')")); + ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (2, 'testing')")); + ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (3, 'nope')")); // Inject corruption into the index. - db().Close(); + db_.Close(); static const char kDeleteSql[] = "DELETE FROM t WHERE id = 3"; - ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path(), "t_id", kDeleteSql)); + ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path_, "t_id", kDeleteSql)); ASSERT_TRUE(Reopen()); // id as read from index. static const char kSelectIndexIdSql[] = "SELECT id FROM t INDEXED BY t_id"; - EXPECT_EQ("1,2,3", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ",")); + EXPECT_EQ("1,2,3", ExecuteWithResults(&db_, kSelectIndexIdSql, "|", ",")); // id as read from table. static const char kSelectTableIdSql[] = "SELECT id FROM t NOT INDEXED"; - EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ",")); + EXPECT_EQ("1,2", ExecuteWithResults(&db_, kSelectTableIdSql, "|", ",")); // Run recovery code, then rollback. Database remains the same. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::BeginRecoverDatabase(&db(), db_path()); + std::unique_ptr<Recovery> recovery = + Recovery::BeginRecoverDatabase(&db_, db_path_); ASSERT_TRUE(recovery); - sql::Recovery::Rollback(std::move(recovery)); + Recovery::Rollback(std::move(recovery)); } - db().Close(); + db_.Close(); ASSERT_TRUE(Reopen()); - EXPECT_EQ("1,2,3", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ",")); - EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ",")); + EXPECT_EQ("1,2,3", ExecuteWithResults(&db_, kSelectIndexIdSql, "|", ",")); + EXPECT_EQ("1,2", ExecuteWithResults(&db_, kSelectTableIdSql, "|", ",")); // Run recovery code, then commit. The failing row is dropped. { - std::unique_ptr<sql::Recovery> recovery = - sql::Recovery::BeginRecoverDatabase(&db(), db_path()); + std::unique_ptr<Recovery> recovery = + Recovery::BeginRecoverDatabase(&db_, db_path_); ASSERT_TRUE(recovery); - ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); + ASSERT_TRUE(Recovery::Recovered(std::move(recovery))); } - db().Close(); + db_.Close(); ASSERT_TRUE(Reopen()); - EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ",")); - EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ",")); + EXPECT_EQ("1,2", ExecuteWithResults(&db_, kSelectIndexIdSql, "|", ",")); + EXPECT_EQ("1,2", ExecuteWithResults(&db_, kSelectTableIdSql, "|", ",")); } // Test histograms recorded when the invalid database cannot be attached. TEST_F(SQLRecoveryTest, AttachFailure) { // Create a valid database, then write junk over the header. This should lead // to SQLITE_NOTADB, which will cause ATTACH to fail. - ASSERT_TRUE(db().Execute("CREATE TABLE x (t TEXT)")); - ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test')")); - db().Close(); - WriteJunkToDatabase(SQLTestBase::TYPE_OVERWRITE); + ASSERT_TRUE(db_.Execute("CREATE TABLE x (t TEXT)")); + ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')")); + db_.Close(); + ASSERT_TRUE(OverwriteDatabaseHeader()); static const char kEventHistogramName[] = "Sqlite.RecoveryEvents"; const int kEventEnum = 5; // RECOVERY_FAILED_ATTACH @@ -914,8 +924,7 @@ TEST_F(SQLRecoveryTest, AttachFailure) { ASSERT_TRUE(Reopen()); // Begin() should fail. - std::unique_ptr<sql::Recovery> - recovery = sql::Recovery::Begin(&db(), db_path()); + std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_); ASSERT_FALSE(recovery.get()); ASSERT_TRUE(expecter.SawExpectedErrors()); @@ -942,8 +951,8 @@ void TestPageSize(const base::FilePath& db_prefix, const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII( base::NumberToString(initial_page_size)); - sql::Database::Delete(db_path); - sql::Database db({.page_size = initial_page_size}); + Database::Delete(db_path); + Database db({.page_size = initial_page_size}); ASSERT_TRUE(db.Open(db_path)); ASSERT_TRUE(db.Execute(kCreateSql)); ASSERT_TRUE(db.Execute(kInsertSql1)); @@ -953,18 +962,17 @@ void TestPageSize(const base::FilePath& db_prefix, db.Close(); // Re-open the database while setting a new |options.page_size| in the object. - sql::Database recover_db({.page_size = final_page_size}); + Database recover_db({.page_size = final_page_size}); ASSERT_TRUE(recover_db.Open(db_path)); // Recovery will use the page size set in the database object, which may not // match the file's page size. - sql::Recovery::RecoverDatabase(&recover_db, db_path); + Recovery::RecoverDatabase(&recover_db, db_path); // Recovery poisoned the handle, must re-open. recover_db.Close(); // Make sure the page size is read from the file. - sql::Database recovered_db( - {.page_size = sql::DatabaseOptions::kDefaultPageSize}); + Database recovered_db({.page_size = DatabaseOptions::kDefaultPageSize}); ASSERT_TRUE(recovered_db.Open(db_path)); ASSERT_EQ(expected_final_page_size, ExecuteWithResult(&recovered_db, "PRAGMA page_size")); @@ -972,34 +980,36 @@ void TestPageSize(const base::FilePath& db_prefix, ExecuteWithResults(&recovered_db, kSelectSql, "|", "\n")); } -// Verify that sql::Recovery maintains the page size, and the virtual table +// Verify that Recovery maintains the page size, and the virtual table // works with page sizes other than SQLite's default. Also verify the case // where the default page size has changed. TEST_F(SQLRecoveryTest, PageSize) { const std::string default_page_size = - ExecuteWithResult(&db(), "PRAGMA page_size"); + ExecuteWithResult(&db_, "PRAGMA page_size"); // Check the default page size first. EXPECT_NO_FATAL_FAILURE(TestPageSize( - db_path(), sql::DatabaseOptions::kDefaultPageSize, default_page_size, - sql::DatabaseOptions::kDefaultPageSize, default_page_size)); + db_path_, DatabaseOptions::kDefaultPageSize, default_page_size, + DatabaseOptions::kDefaultPageSize, default_page_size)); // Sync uses 32k pages. EXPECT_NO_FATAL_FAILURE( - TestPageSize(db_path(), 32768, "32768", 32768, "32768")); + TestPageSize(db_path_, 32768, "32768", 32768, "32768")); // Many clients use 4k pages. This is the SQLite default after 3.12.0. - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 4096, "4096", 4096, "4096")); + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 4096, "4096", 4096, "4096")); // 1k is the default page size before 3.12.0. - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 1024, "1024", 1024, "1024")); + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 1024, "1024", 1024, "1024")); // Databases with no page size specified should recover with the new default // page size. 2k has never been the default page size. ASSERT_NE("2048", default_page_size); - EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 2048, "2048", - sql::DatabaseOptions::kDefaultPageSize, + EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048", + DatabaseOptions::kDefaultPageSize, default_page_size)); } } // namespace + +} // namespace sql diff --git a/chromium/sql/sandboxed_vfs.cc b/chromium/sql/sandboxed_vfs.cc index 906a11c68a2..145efad294b 100644 --- a/chromium/sql/sandboxed_vfs.cc +++ b/chromium/sql/sandboxed_vfs.cc @@ -165,7 +165,7 @@ int SandboxedVfs::Delete(const char* full_path, int sync_dir) { int SandboxedVfs::Access(const char* full_path, int flags, int& result) { DCHECK(full_path); - base::Optional<PathAccessInfo> access = + absl::optional<PathAccessInfo> access = delegate_->GetPathAccess(base::FilePath::FromUTF8Unsafe(full_path)); if (!access) { result = 0; diff --git a/chromium/sql/sandboxed_vfs.h b/chromium/sql/sandboxed_vfs.h index a7eed6288de..fd787b12225 100644 --- a/chromium/sql/sandboxed_vfs.h +++ b/chromium/sql/sandboxed_vfs.h @@ -12,7 +12,7 @@ #include "base/component_export.h" #include "base/files/file.h" #include "base/files/file_path.h" -#include "base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/sqlite/sqlite3.h" namespace sql { @@ -57,7 +57,7 @@ class COMPONENT_EXPORT(SQL) SandboxedVfs { // Queries path access information for `file_path`. Returns null if the // given path does not exist. - virtual base::Optional<PathAccessInfo> GetPathAccess( + virtual absl::optional<PathAccessInfo> GetPathAccess( const base::FilePath& file_path) = 0; // Resizes a file. diff --git a/chromium/sql/sql_memory_dump_provider.h b/chromium/sql/sql_memory_dump_provider.h index 57e88c67f16..190b802adf8 100644 --- a/chromium/sql/sql_memory_dump_provider.h +++ b/chromium/sql/sql_memory_dump_provider.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SQL_SQL_MEMORY_DUMP_PROVIDER_H -#define SQL_SQL_MEMORY_DUMP_PROVIDER_H +#ifndef SQL_SQL_MEMORY_DUMP_PROVIDER_H_ +#define SQL_SQL_MEMORY_DUMP_PROVIDER_H_ #include "base/component_export.h" #include "base/macros.h" @@ -34,4 +34,4 @@ class COMPONENT_EXPORT(SQL) SqlMemoryDumpProvider } // namespace sql -#endif // SQL_SQL_MEMORY_DUMP_PROVIDER_H +#endif // SQL_SQL_MEMORY_DUMP_PROVIDER_H_ diff --git a/chromium/sql/sql_memory_dump_provider_unittest.cc b/chromium/sql/sql_memory_dump_provider_unittest.cc index c361253b0d1..6929639c7e9 100644 --- a/chromium/sql/sql_memory_dump_provider_unittest.cc +++ b/chromium/sql/sql_memory_dump_provider_unittest.cc @@ -4,19 +4,41 @@ #include "sql/sql_memory_dump_provider.h" +#include "base/files/scoped_temp_dir.h" +#include "base/trace_event/memory_dump_request_args.h" #include "base/trace_event/process_memory_dump.h" -#include "sql/test/sql_test_base.h" +#include "sql/database.h" #include "testing/gtest/include/gtest/gtest.h" +namespace sql { + namespace { -using SQLMemoryDumpProviderTest = sql::SQLTestBase; -} + +class SQLMemoryDumpProviderTest : public testing::Test { + public: + ~SQLMemoryDumpProviderTest() override = default; + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE(db_.Open( + temp_dir_.GetPath().AppendASCII("memory_dump_provider_test.sqlite"))); + + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a, b)")); + } + + protected: + base::ScopedTempDir temp_dir_; + Database db_; +}; TEST_F(SQLMemoryDumpProviderTest, OnMemoryDump) { base::trace_event::MemoryDumpArgs args = { base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; base::trace_event::ProcessMemoryDump pmd(args); - ASSERT_TRUE( - sql::SqlMemoryDumpProvider::GetInstance()->OnMemoryDump(args, &pmd)); + ASSERT_TRUE(SqlMemoryDumpProvider::GetInstance()->OnMemoryDump(args, &pmd)); ASSERT_TRUE(pmd.GetAllocatorDump("sqlite")); } + +} // namespace + +} // namespace sql diff --git a/chromium/sql/sqlite_features_unittest.cc b/chromium/sql/sqlite_features_unittest.cc index 877ec675c9a..a84a51bb57d 100644 --- a/chromium/sql/sqlite_features_unittest.cc +++ b/chromium/sql/sqlite_features_unittest.cc @@ -8,13 +8,13 @@ #include <string> #include "base/bind.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 "build/build_config.h" #include "sql/database.h" #include "sql/statement.h" -#include "sql/test/sql_test_base.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" @@ -40,16 +40,18 @@ void CaptureErrorCallback(int* error_pointer, std::string* sql_text, } // namespace -class SQLiteFeaturesTest : public sql::SQLTestBase { +class SQLiteFeaturesTest : public testing::Test { public: - SQLiteFeaturesTest() : error_(SQLITE_OK) {} + ~SQLiteFeaturesTest() override = default; void SetUp() override { - SQLTestBase::SetUp(); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_path_ = temp_dir_.GetPath().AppendASCII("sqlite_features_test.sqlite"); + ASSERT_TRUE(db_.Open(db_path_)); // The error delegate will set |error_| and |sql_text_| when any sqlite // statement operation returns an error code. - db().set_error_callback( + db_.set_error_callback( base::BindRepeating(&CaptureErrorCallback, &error_, &sql_text_)); } @@ -57,15 +59,20 @@ class SQLiteFeaturesTest : public sql::SQLTestBase { // If any error happened the original sql statement can be found in // |sql_text_|. EXPECT_EQ(SQLITE_OK, error_) << sql_text_; + } - SQLTestBase::TearDown(); + bool Reopen() { + db_.Close(); + return db_.Open(db_path_); } - int error() { return error_; } + protected: + base::ScopedTempDir temp_dir_; + base::FilePath db_path_; + Database db_; - private: // The error code of the most recent error. - int error_; + int error_ = SQLITE_OK; // Original statement which has caused the error. std::string sql_text_; }; @@ -73,21 +80,20 @@ class SQLiteFeaturesTest : public sql::SQLTestBase { // Do not include fts1 support, it is not useful, and nobody is // looking at it. TEST_F(SQLiteFeaturesTest, NoFTS1) { - ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode( - "CREATE VIRTUAL TABLE foo USING fts1(x)")); + ASSERT_EQ(SQLITE_ERROR, db_.ExecuteAndReturnErrorCode( + "CREATE VIRTUAL TABLE foo USING fts1(x)")); } // Do not include fts2 support, it is not useful, and nobody is // looking at it. TEST_F(SQLiteFeaturesTest, NoFTS2) { - ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode( - "CREATE VIRTUAL TABLE foo USING fts2(x)")); + ASSERT_EQ(SQLITE_ERROR, db_.ExecuteAndReturnErrorCode( + "CREATE VIRTUAL TABLE foo USING fts2(x)")); } -// fts3 used to be used for history files, and may also be used by WebDatabase -// clients. +// fts3 is exposed in WebSQL. TEST_F(SQLiteFeaturesTest, FTS3) { - ASSERT_TRUE(db().Execute("CREATE VIRTUAL TABLE foo USING fts3(x)")); + ASSERT_TRUE(db_.Execute("CREATE VIRTUAL TABLE foo USING fts3(x)")); } // Originally history used fts2, which Chromium patched to treat "foo*" as a @@ -96,12 +102,12 @@ TEST_F(SQLiteFeaturesTest, FTS3) { TEST_F(SQLiteFeaturesTest, FTS3_Prefix) { static const char kCreateSql[] = "CREATE VIRTUAL TABLE foo USING fts3(x, tokenize icu)"; - ASSERT_TRUE(db().Execute(kCreateSql)); + ASSERT_TRUE(db_.Execute(kCreateSql)); - ASSERT_TRUE(db().Execute("INSERT INTO foo (x) VALUES ('test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO foo (x) VALUES ('test')")); EXPECT_EQ("test", - ExecuteWithResult(&db(), "SELECT x FROM foo WHERE x MATCH 'te*'")); + ExecuteWithResult(&db_, "SELECT x FROM foo WHERE x MATCH 'te*'")); } // Verify that Chromium's SQLite is compiled with HAVE_USLEEP defined. With @@ -121,9 +127,9 @@ TEST_F(SQLiteFeaturesTest, UsesUsleep) { // Ensure that our SQLite version has working foreign key support with cascade // delete support. TEST_F(SQLiteFeaturesTest, ForeignKeySupport) { - ASSERT_TRUE(db().Execute("PRAGMA foreign_keys=1")); - ASSERT_TRUE(db().Execute("CREATE TABLE parents (id INTEGER PRIMARY KEY)")); - ASSERT_TRUE(db().Execute( + ASSERT_TRUE(db_.Execute("PRAGMA foreign_keys=1")); + ASSERT_TRUE(db_.Execute("CREATE TABLE parents (id INTEGER PRIMARY KEY)")); + ASSERT_TRUE(db_.Execute( "CREATE TABLE children (" " id INTEGER PRIMARY KEY," " pid INTEGER NOT NULL REFERENCES parents(id) ON DELETE CASCADE)")); @@ -131,40 +137,40 @@ TEST_F(SQLiteFeaturesTest, ForeignKeySupport) { static const char kSelectChildrenSql[] = "SELECT * FROM children ORDER BY id"; // Inserting without a matching parent should fail with constraint violation. - EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParentsSql)); + EXPECT_EQ("", ExecuteWithResult(&db_, kSelectParentsSql)); const int insert_error = - db().ExecuteAndReturnErrorCode("INSERT INTO children VALUES (10, 1)"); + db_.ExecuteAndReturnErrorCode("INSERT INTO children VALUES (10, 1)"); EXPECT_EQ(SQLITE_CONSTRAINT | SQLITE_CONSTRAINT_FOREIGNKEY, insert_error); - EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildrenSql)); + EXPECT_EQ("", ExecuteWithResult(&db_, kSelectChildrenSql)); // Inserting with a matching parent should work. - ASSERT_TRUE(db().Execute("INSERT INTO parents VALUES (1)")); - EXPECT_EQ("1", ExecuteWithResults(&db(), kSelectParentsSql, "|", "\n")); - EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (11, 1)")); - EXPECT_TRUE(db().Execute("INSERT INTO children VALUES (12, 1)")); + ASSERT_TRUE(db_.Execute("INSERT INTO parents VALUES (1)")); + EXPECT_EQ("1", ExecuteWithResults(&db_, kSelectParentsSql, "|", "\n")); + EXPECT_TRUE(db_.Execute("INSERT INTO children VALUES (11, 1)")); + EXPECT_TRUE(db_.Execute("INSERT INTO children VALUES (12, 1)")); EXPECT_EQ("11|1\n12|1", - ExecuteWithResults(&db(), kSelectChildrenSql, "|", "\n")); + ExecuteWithResults(&db_, kSelectChildrenSql, "|", "\n")); // Deleting the parent should cascade, deleting the children as well. - ASSERT_TRUE(db().Execute("DELETE FROM parents")); - EXPECT_EQ("", ExecuteWithResult(&db(), kSelectParentsSql)); - EXPECT_EQ("", ExecuteWithResult(&db(), kSelectChildrenSql)); + ASSERT_TRUE(db_.Execute("DELETE FROM parents")); + EXPECT_EQ("", ExecuteWithResult(&db_, kSelectParentsSql)); + EXPECT_EQ("", ExecuteWithResult(&db_, kSelectChildrenSql)); } // Ensure that our SQLite version supports booleans. TEST_F(SQLiteFeaturesTest, BooleanSupport) { ASSERT_TRUE( - db().Execute("CREATE TABLE flags (" - " id INTEGER PRIMARY KEY," - " true_flag BOOL NOT NULL DEFAULT TRUE," - " false_flag BOOL NOT NULL DEFAULT FALSE)")); - ASSERT_TRUE(db().Execute( + db_.Execute("CREATE TABLE flags (" + " id INTEGER PRIMARY KEY," + " true_flag BOOL NOT NULL DEFAULT TRUE," + " false_flag BOOL NOT NULL DEFAULT FALSE)")); + ASSERT_TRUE(db_.Execute( "ALTER TABLE flags ADD COLUMN true_flag2 BOOL NOT NULL DEFAULT TRUE")); - ASSERT_TRUE(db().Execute( + ASSERT_TRUE(db_.Execute( "ALTER TABLE flags ADD COLUMN false_flag2 BOOL NOT NULL DEFAULT FALSE")); - ASSERT_TRUE(db().Execute("INSERT INTO flags (id) VALUES (1)")); + ASSERT_TRUE(db_.Execute("INSERT INTO flags (id) VALUES (1)")); - sql::Statement s(db().GetUniqueStatement( + sql::Statement s(db_.GetUniqueStatement( "SELECT true_flag, false_flag, true_flag2, false_flag2" " FROM flags WHERE id=1;")); ASSERT_TRUE(s.Step()); @@ -177,13 +183,11 @@ TEST_F(SQLiteFeaturesTest, BooleanSupport) { } TEST_F(SQLiteFeaturesTest, IcuEnabled) { - sql::Statement lower_en( - db().GetUniqueStatement("SELECT lower('I', 'en_us')")); + sql::Statement lower_en(db_.GetUniqueStatement("SELECT lower('I', 'en_us')")); ASSERT_TRUE(lower_en.Step()); EXPECT_EQ("i", lower_en.ColumnString(0)); - sql::Statement lower_tr( - db().GetUniqueStatement("SELECT lower('I', 'tr_tr')")); + sql::Statement lower_tr(db_.GetUniqueStatement("SELECT lower('I', 'tr_tr')")); ASSERT_TRUE(lower_tr.Step()); EXPECT_EQ("\u0131", lower_tr.ColumnString(0)); } @@ -196,14 +200,14 @@ TEST_F(SQLiteFeaturesTest, IcuEnabled) { // be disabled on this platform using SQLITE_MAX_MMAP_SIZE=0. TEST_F(SQLiteFeaturesTest, Mmap) { // Try to turn on mmap'ed I/O. - ignore_result(db().Execute("PRAGMA mmap_size = 1048576")); + ignore_result(db_.Execute("PRAGMA mmap_size = 1048576")); { - sql::Statement s(db().GetUniqueStatement("PRAGMA mmap_size")); + sql::Statement s(db_.GetUniqueStatement("PRAGMA mmap_size")); ASSERT_TRUE(s.Step()); ASSERT_GT(s.ColumnInt64(0), 0); } - db().Close(); + db_.Close(); const uint32_t kFlags = base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE; @@ -211,7 +215,7 @@ TEST_F(SQLiteFeaturesTest, Mmap) { // Create a file with a block of '0', a block of '1', and a block of '2'. { - base::File f(db_path(), kFlags); + base::File f(db_path_, kFlags); ASSERT_TRUE(f.IsValid()); memset(buf, '0', sizeof(buf)); ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); @@ -226,7 +230,7 @@ TEST_F(SQLiteFeaturesTest, Mmap) { // mmap the file and verify that everything looks right. { base::MemoryMappedFile m; - ASSERT_TRUE(m.Initialize(db_path())); + ASSERT_TRUE(m.Initialize(db_path_)); memset(buf, '0', sizeof(buf)); ASSERT_EQ(0, memcmp(buf, m.data() + 0*sizeof(buf), sizeof(buf))); @@ -240,7 +244,7 @@ TEST_F(SQLiteFeaturesTest, Mmap) { // Scribble some '3' into the first page of the file, and verify that it // looks the same in the memory mapping. { - base::File f(db_path(), kFlags); + base::File f(db_path_, kFlags); ASSERT_TRUE(f.IsValid()); memset(buf, '3', sizeof(buf)); ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf)); @@ -251,7 +255,7 @@ TEST_F(SQLiteFeaturesTest, Mmap) { const size_t kOffset = 1*sizeof(buf) + 123; ASSERT_NE('4', m.data()[kOffset]); { - base::File f(db_path(), kFlags); + base::File f(db_path_, kFlags); ASSERT_TRUE(f.IsValid()); buf[0] = '4'; ASSERT_EQ(f.Write(kOffset, buf, 1), 1); @@ -264,14 +268,14 @@ TEST_F(SQLiteFeaturesTest, Mmap) { // compiled regular expression is effectively cached with the prepared // statement, causing errors if the regular expression is rebound. TEST_F(SQLiteFeaturesTest, CachedRegexp) { - ASSERT_TRUE(db().Execute("CREATE TABLE r (id INTEGER UNIQUE, x TEXT)")); - ASSERT_TRUE(db().Execute("INSERT INTO r VALUES (1, 'this is a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO r VALUES (2, 'that was a test')")); - ASSERT_TRUE(db().Execute("INSERT INTO r VALUES (3, 'this is a stickup')")); - ASSERT_TRUE(db().Execute("INSERT INTO r VALUES (4, 'that sucks')")); + ASSERT_TRUE(db_.Execute("CREATE TABLE r (id INTEGER UNIQUE, x TEXT)")); + ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (1, 'this is a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (2, 'that was a test')")); + ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (3, 'this is a stickup')")); + ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (4, 'that sucks')")); static const char kSimpleSql[] = "SELECT SUM(id) FROM r WHERE x REGEXP ?"; - sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, kSimpleSql)); s.BindString(0, "this.*"); ASSERT_TRUE(s.Step()); @@ -297,26 +301,26 @@ TEST_F(SQLiteFeaturesTest, CachedRegexp) { // If a database file is marked to be excluded from Time Machine, verify that // journal files are also excluded. TEST_F(SQLiteFeaturesTest, TimeMachine) { - ASSERT_TRUE(db().Execute("CREATE TABLE t (id INTEGER PRIMARY KEY)")); - db().Close(); + ASSERT_TRUE(db_.Execute("CREATE TABLE t (id INTEGER PRIMARY KEY)")); + db_.Close(); - base::FilePath journal_path = sql::Database::JournalPath(db_path()); - ASSERT_TRUE(GetPathExists(db_path())); - ASSERT_TRUE(GetPathExists(journal_path)); + 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::mac::GetFileBackupExclusion(db_path())); + EXPECT_FALSE(base::mac::GetFileBackupExclusion(db_path_)); EXPECT_FALSE(base::mac::GetFileBackupExclusion(journal_path)); // Exclude the main database file. - EXPECT_TRUE(base::mac::SetFileBackupExclusion(db_path())); + EXPECT_TRUE(base::mac::SetFileBackupExclusion(db_path_)); - EXPECT_TRUE(base::mac::GetFileBackupExclusion(db_path())); + EXPECT_TRUE(base::mac::GetFileBackupExclusion(db_path_)); EXPECT_FALSE(base::mac::GetFileBackupExclusion(journal_path)); - EXPECT_TRUE(db().Open(db_path())); - ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (1)")); - EXPECT_TRUE(base::mac::GetFileBackupExclusion(db_path())); + EXPECT_TRUE(db_.Open(db_path_)); + ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (1)")); + EXPECT_TRUE(base::mac::GetFileBackupExclusion(db_path_)); EXPECT_TRUE(base::mac::GetFileBackupExclusion(journal_path)); // TODO(shess): In WAL mode this will touch -wal and -shm files. -shm files @@ -329,30 +333,30 @@ TEST_F(SQLiteFeaturesTest, TimeMachine) { // 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 = sql::Database::WriteAheadLogPath(db_path()); + base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path_); // 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")); + 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)")); + 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)); + ASSERT_TRUE(base::PathExists(wal_path)); + db_.Close(); + ASSERT_FALSE(base::PathExists(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, - nullptr)); - ASSERT_TRUE(GetPathExists(wal_path)); - db().Close(); - ASSERT_TRUE(GetPathExists(wal_path)); + 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, nullptr)); + ASSERT_TRUE(base::PathExists(wal_path)); + db_.Close(); + ASSERT_TRUE(base::PathExists(wal_path)); } #endif diff --git a/chromium/sql/statement.cc b/chromium/sql/statement.cc index 87c2b120796..fe8ae340aaf 100644 --- a/chromium/sql/statement.cc +++ b/chromium/sql/statement.cc @@ -79,7 +79,7 @@ int Statement::StepInternal() { if (!CheckValid()) return SQLITE_ERROR; - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); stepped_ = true; @@ -109,7 +109,7 @@ void Statement::Reset(bool clear_bound_vars) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); #endif // OS_ANDROID - base::Optional<base::ScopedBlockingCall> scoped_blocking_call; + absl::optional<base::ScopedBlockingCall> scoped_blocking_call; ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call); if (is_valid()) { if (clear_bound_vars) diff --git a/chromium/sql/statement_unittest.cc b/chromium/sql/statement_unittest.cc index 2033ee367e9..af85326ea2d 100644 --- a/chromium/sql/statement_unittest.cc +++ b/chromium/sql/statement_unittest.cc @@ -11,29 +11,40 @@ #include "sql/statement.h" #include "sql/test/error_callback_support.h" #include "sql/test/scoped_error_expecter.h" -#include "sql/test/sql_test_base.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" +namespace sql { namespace { -using SQLStatementTest = sql::SQLTestBase; +class SQLStatementTest : public testing::Test { + public: + ~SQLStatementTest() override = default; -} // namespace + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + db_.Open(temp_dir_.GetPath().AppendASCII("statement_test.sqlite"))); + } + + protected: + base::ScopedTempDir temp_dir_; + Database db_; +}; TEST_F(SQLStatementTest, Assign) { - sql::Statement s; + Statement s; EXPECT_FALSE(s.is_valid()); - s.Assign(db().GetUniqueStatement("CREATE TABLE foo (a, b)")); + s.Assign(db_.GetUniqueStatement("CREATE TABLE foo (a, b)")); EXPECT_TRUE(s.is_valid()); } TEST_F(SQLStatementTest, Run) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (3, 12)")); - sql::Statement s(db().GetUniqueStatement("SELECT b FROM foo WHERE a=?")); + Statement s(db_.GetUniqueStatement("SELECT b FROM foo WHERE a=?")); EXPECT_FALSE(s.Succeeded()); // Stepping it won't work since we haven't bound the value. @@ -44,7 +55,7 @@ TEST_F(SQLStatementTest, Run) { s.Reset(true); s.BindInt(0, 3); EXPECT_FALSE(s.Run()); - EXPECT_EQ(SQLITE_ROW, db().GetErrorCode()); + EXPECT_EQ(SQLITE_ROW, db_.GetErrorCode()); EXPECT_TRUE(s.Succeeded()); // Resetting it should put it back to the previous state (not runnable). @@ -62,16 +73,16 @@ TEST_F(SQLStatementTest, Run) { // Error callback called for error running a statement. TEST_F(SQLStatementTest, ErrorCallback) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)")); int error = SQLITE_OK; - sql::ScopedErrorCallback sec( - &db(), base::BindRepeating(&sql::CaptureErrorCallback, &error)); + ScopedErrorCallback sec(&db_, + base::BindRepeating(&CaptureErrorCallback, &error)); // Insert in the foo table the primary key. It is an error to insert // something other than an number. This error causes the error callback // handler to be called with SQLITE_MISMATCH as error code. - sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)")); + Statement s(db_.GetUniqueStatement("INSERT INTO foo (a) VALUES (?)")); EXPECT_TRUE(s.is_valid()); s.BindCString(0, "bad bad"); EXPECT_FALSE(s.Run()); @@ -80,9 +91,9 @@ TEST_F(SQLStatementTest, ErrorCallback) { // Error expecter works for error running a statement. TEST_F(SQLStatementTest, ScopedIgnoreError) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)")); - sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)")); + Statement s(db_.GetUniqueStatement("INSERT INTO foo (a) VALUES (?)")); EXPECT_TRUE(s.is_valid()); { @@ -95,12 +106,11 @@ TEST_F(SQLStatementTest, ScopedIgnoreError) { } TEST_F(SQLStatementTest, Reset) { - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)")); - ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (4, 13)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (3, 12)")); + ASSERT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (4, 13)")); - sql::Statement s(db().GetUniqueStatement( - "SELECT b FROM foo WHERE a = ? ")); + Statement s(db_.GetUniqueStatement("SELECT b FROM foo WHERE a = ? ")); s.BindInt(0, 3); ASSERT_TRUE(s.Step()); EXPECT_EQ(12, s.ColumnInt(0)); @@ -115,3 +125,6 @@ TEST_F(SQLStatementTest, Reset) { s.Reset(true); ASSERT_FALSE(s.Step()); } + +} // namespace +} // namespace sql diff --git a/chromium/sql/transaction_unittest.cc b/chromium/sql/transaction_unittest.cc index bcc05f5815b..48f75da20b2 100644 --- a/chromium/sql/transaction_unittest.cc +++ b/chromium/sql/transaction_unittest.cc @@ -3,38 +3,50 @@ // found in the LICENSE file. #include "sql/transaction.h" + #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "sql/database.h" #include "sql/statement.h" -#include "sql/test/sql_test_base.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" -class SQLTransactionTest : public sql::SQLTestBase { +namespace sql { + +namespace { + +class SQLTransactionTest : public testing::Test { public: + ~SQLTransactionTest() override = default; + void SetUp() override { - SQLTestBase::SetUp(); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE( + db_.Open(temp_dir_.GetPath().AppendASCII("transaction_test.sqlite"))); - ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); + ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a, b)")); } // Returns the number of rows in table "foo". int CountFoo() { - sql::Statement count(db().GetUniqueStatement("SELECT count(*) FROM foo")); + Statement count(db_.GetUniqueStatement("SELECT count(*) FROM foo")); count.Step(); return count.ColumnInt(0); } + + protected: + base::ScopedTempDir temp_dir_; + Database db_; }; TEST_F(SQLTransactionTest, Commit) { { - sql::Transaction t(&db()); + Transaction t(&db_); EXPECT_FALSE(t.is_open()); EXPECT_TRUE(t.Begin()); EXPECT_TRUE(t.is_open()); - EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); + EXPECT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); t.Commit(); EXPECT_FALSE(t.is_open()); @@ -47,23 +59,23 @@ TEST_F(SQLTransactionTest, Rollback) { // Test some basic initialization, and that rollback runs when you exit the // scope. { - sql::Transaction t(&db()); + Transaction t(&db_); EXPECT_FALSE(t.is_open()); EXPECT_TRUE(t.Begin()); EXPECT_TRUE(t.is_open()); - EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); + EXPECT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); } // Nothing should have been committed since it was implicitly rolled back. EXPECT_EQ(0, CountFoo()); // Test explicit rollback. - sql::Transaction t2(&db()); + Transaction t2(&db_); EXPECT_FALSE(t2.is_open()); EXPECT_TRUE(t2.Begin()); - EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); + EXPECT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); t2.Rollback(); EXPECT_FALSE(t2.is_open()); @@ -73,23 +85,23 @@ TEST_F(SQLTransactionTest, Rollback) { // Rolling back any part of a transaction should roll back all of them. TEST_F(SQLTransactionTest, NestedRollback) { - EXPECT_EQ(0, db().transaction_nesting()); + EXPECT_EQ(0, db_.transaction_nesting()); // Outermost transaction. { - sql::Transaction outer(&db()); + Transaction outer(&db_); EXPECT_TRUE(outer.Begin()); - EXPECT_EQ(1, db().transaction_nesting()); + EXPECT_EQ(1, db_.transaction_nesting()); // The first inner one gets committed. { - sql::Transaction inner1(&db()); + Transaction inner1(&db_); EXPECT_TRUE(inner1.Begin()); - EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); - EXPECT_EQ(2, db().transaction_nesting()); + EXPECT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); + EXPECT_EQ(2, db_.transaction_nesting()); inner1.Commit(); - EXPECT_EQ(1, db().transaction_nesting()); + EXPECT_EQ(1, db_.transaction_nesting()); } // One row should have gotten inserted. @@ -97,24 +109,28 @@ TEST_F(SQLTransactionTest, NestedRollback) { // The second inner one gets rolled back. { - sql::Transaction inner2(&db()); + Transaction inner2(&db_); EXPECT_TRUE(inner2.Begin()); - EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); - EXPECT_EQ(2, db().transaction_nesting()); + EXPECT_TRUE(db_.Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); + EXPECT_EQ(2, db_.transaction_nesting()); inner2.Rollback(); - EXPECT_EQ(1, db().transaction_nesting()); + EXPECT_EQ(1, db_.transaction_nesting()); } // A third inner one will fail in Begin since one has already been rolled // back. - EXPECT_EQ(1, db().transaction_nesting()); + EXPECT_EQ(1, db_.transaction_nesting()); { - sql::Transaction inner3(&db()); + Transaction inner3(&db_); EXPECT_FALSE(inner3.Begin()); - EXPECT_EQ(1, db().transaction_nesting()); + EXPECT_EQ(1, db_.transaction_nesting()); } } - EXPECT_EQ(0, db().transaction_nesting()); + EXPECT_EQ(0, db_.transaction_nesting()); EXPECT_EQ(0, CountFoo()); } + +} // namespace + +} // namespace sql |