blob: 2dc026cc924b2e59f3439ab5002b523d3d1dbcd8 [file] [log] [blame]
// 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_