1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// 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/check_op.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) {
#if 0
static_assert(std::is_standard_layout<VirtualCursor>::value,
"needed for the reinterpret_cast below");
#endif
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_
|