| // Copyright 2019 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef SQL_RECOVER_MODULE_CURSOR_H_ | 
 | #define SQL_RECOVER_MODULE_CURSOR_H_ | 
 |  | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/sequence_checker.h" | 
 | #include "sql/recover_module/btree.h" | 
 | #include "sql/recover_module/pager.h" | 
 | #include "sql/recover_module/parsing.h" | 
 | #include "sql/recover_module/payload.h" | 
 | #include "sql/recover_module/record.h" | 
 | #include "third_party/sqlite/sqlite3.h" | 
 |  | 
 | namespace sql { | 
 | namespace recover { | 
 |  | 
 | class VirtualTable; | 
 |  | 
 | // Represents a virtual table cursor created by SQLite in a recovery table. | 
 | // | 
 | // Instances are allocated on the heap using the C++ new operator, and passed to | 
 | // SQLite via pointers to the sqlite_vtab members. SQLite is responsible for | 
 | // managing the instances' lifetimes. SQLite will call xClose() for every | 
 | // successful xOpen(). | 
 | // | 
 | // Instances are not thread-safe. This should be fine, as long as each SQLite | 
 | // statement that reads from a virtual table is only used on one sequence. This | 
 | // assumption is verified by a sequence checker. | 
 | // | 
 | // If it turns out that VirtualCursor needs to be thread-safe, the best solution | 
 | // is to add a base::Lock to VirtualCursor, and keep all underlying classes not | 
 | // thread-safe. | 
 | class VirtualCursor { | 
 |  public: | 
 |   // Creates a cursor that iterates over |table|. | 
 |   // | 
 |   // |table| must outlive this instance. SQLite is trusted to call xClose() for | 
 |   // this cursor before calling xDestroy() / xDisconnect() for the virtual table | 
 |   // related to the cursor. | 
 |   explicit VirtualCursor(VirtualTable* table); | 
 |   ~VirtualCursor(); | 
 |  | 
 |   VirtualCursor(const VirtualCursor&) = delete; | 
 |   VirtualCursor& operator=(const VirtualCursor&) = delete; | 
 |  | 
 |   // Returns the embedded SQLite virtual table cursor. | 
 |   // | 
 |   // This getter is not const because SQLite wants a non-const pointer to the | 
 |   // structure. | 
 |   sqlite3_vtab_cursor* SqliteCursor() { return &sqlite_cursor_; } | 
 |  | 
 |   // The VirtualCursor instance that embeds a given SQLite virtual table cursor. | 
 |   // | 
 |   // |sqlite_cursor| must have been returned by VirtualTable::SqliteCursor(). | 
 |   static inline VirtualCursor* FromSqliteCursor( | 
 |       sqlite3_vtab_cursor* sqlite_cursor) { | 
 |     static_assert(std::is_standard_layout<VirtualCursor>::value, | 
 |                   "needed for the reinterpret_cast below"); | 
 |     static_assert(offsetof(VirtualCursor, sqlite_cursor_) == 0, | 
 |                   "sqlite_cursor_ must be the first member of the class"); | 
 |     VirtualCursor* result = reinterpret_cast<VirtualCursor*>(sqlite_cursor); | 
 |     DCHECK_EQ(sqlite_cursor, &result->sqlite_cursor_); | 
 |     return result; | 
 |   } | 
 |  | 
 |   // Seeks the cursor to the first readable row. Returns a SQLite status code. | 
 |   int First(); | 
 |  | 
 |   // Seeks the cursor to the next row. Returns a SQLite status code. | 
 |   int Next(); | 
 |  | 
 |   // Returns true if the cursor points to a valid row, false otherwise. | 
 |   bool IsValid() const { | 
 |     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 
 |     return record_reader_.IsInitialized(); | 
 |   } | 
 |  | 
 |   // Reports a value in the record to SQLite. |column_index| is 0-based. | 
 |   // | 
 |   // Returns a SQLite error code. This method can fail can happen if a value is | 
 |   // stored across overflow pages, and reading one of the overflow pages results | 
 |   // in an I/O error. | 
 |   int ReadColumn(int column_index, sqlite3_context* result_context); | 
 |  | 
 |   // Returns the rowid of the current row. The cursor must point to a valid row. | 
 |   int64_t RowId(); | 
 |  | 
 |  private: | 
 |   // Appends a decoder for the given page at the end of the current chain. | 
 |   // | 
 |   // No modification is performed in case of failures due to I/O errors or | 
 |   // database corruption. | 
 |   void AppendPageDecoder(int page_id); | 
 |  | 
 |   // True if the current record is acceptable given the recovery schema. | 
 |   bool IsAcceptableRecord(); | 
 |  | 
 |   // SQLite handle for this cursor. The struct is populated and used by SQLite. | 
 |   sqlite3_vtab_cursor sqlite_cursor_; | 
 |  | 
 |   // The table this cursor was created for. | 
 |   // | 
 |   // Raw pointer usage is acceptable because SQLite will ensure that the | 
 |   // VirtualTable, which is passed around as a sqlite3_vtab*, will outlive this | 
 |   // cursor, which is passed around as a sqlite3_cursor*. | 
 |   VirtualTable* const table_; | 
 |  | 
 |   // Reads database pages for this cursor. | 
 |   DatabasePageReader db_reader_; | 
 |  | 
 |   // Reads record payloads for this cursor. | 
 |   LeafPayloadReader payload_reader_; | 
 |  | 
 |   // Reads record rows for this cursor. | 
 |   RecordReader record_reader_; | 
 |  | 
 |   // Decoders for the current chain of inner pages. | 
 |   // | 
 |   // The current chain of pages consists of the inner page decoders here and the | 
 |   // decoder in |leaf_decoder_|. | 
 |   std::vector<std::unique_ptr<InnerPageDecoder>> inner_decoders_; | 
 |  | 
 |   // Decodes the leaf page containing records. | 
 |   std::unique_ptr<LeafPageDecoder> leaf_decoder_; | 
 |  | 
 |   SEQUENCE_CHECKER(sequence_checker_); | 
 | }; | 
 |  | 
 | }  // namespace recover | 
 | }  // namespace sql | 
 |  | 
 | #endif  // SQL_RECOVER_MODULE_CURSOR_H_ |