forked from Pissandshittium/pissandshittium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatement.h
293 lines (244 loc) · 11.6 KB
/
statement.h
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SQL_STATEMENT_H_
#define SQL_STATEMENT_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/dcheck_is_on.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/strings/string_piece.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "sql/database.h"
namespace sql {
enum class SqliteResultCode : int;
// Possible return values from ColumnType in a statement. These should match
// the values in sqlite3.h.
enum class ColumnType {
kInteger = 1,
kFloat = 2,
kText = 3,
kBlob = 4,
kNull = 5,
};
// Compiles and executes SQL statements.
//
// This class is not thread-safe. An instance must be accessed from a single
// sequence. This is enforced in DCHECK-enabled builds.
//
// Normal usage:
// sql::Statement s(connection_.GetUniqueStatement(...));
// s.BindInt(0, a);
// if (s.Step())
// return s.ColumnString(0);
//
// If there are errors getting the statement, the statement will be inert; no
// mutating or database-access methods will work. If you need to check for
// validity, use:
// if (!s.is_valid())
// return false;
//
// Step() and Run() just return true to signal success. If you want to handle
// specific errors such as database corruption, install an error handler in
// in the connection object using set_error_delegate().
class COMPONENT_EXPORT(SQL) Statement {
public:
// Creates an uninitialized statement. The statement will be invalid until
// you initialize it via Assign.
Statement();
explicit Statement(scoped_refptr<Database::StatementRef> ref);
Statement(const Statement&) = delete;
Statement& operator=(const Statement&) = delete;
Statement(Statement&&) = delete;
Statement& operator=(Statement&&) = delete;
~Statement();
// Initializes this object with the given statement, which may or may not
// be valid. Use is_valid() to check if it's OK.
void Assign(scoped_refptr<Database::StatementRef> ref);
// Resets the statement to an uninitialized state corresponding to
// the default constructor, releasing the StatementRef.
void Clear();
// Returns true if the statement can be executed. All functions can still
// be used if the statement is invalid, but they will return failure or some
// default value. This is because the statement can become invalid in the
// middle of executing a command if there is a serious error and the database
// has to be reset.
bool is_valid() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ref_->is_valid();
}
// Running -------------------------------------------------------------------
// Executes the statement, returning true on success. This is like Step but
// for when there is no output, like an INSERT statement.
bool Run();
// Executes the statement, returning true if there is a row of data returned.
// You can keep calling Step() until it returns false to iterate through all
// the rows in your result set.
//
// When Step returns false, the result is either that there is no more data
// or there is an error. This makes it most convenient for loop usage. If you
// need to disambiguate these cases, use Succeeded().
//
// Typical example:
// while (s.Step()) {
// ...
// }
// return s.Succeeded();
bool Step();
// Resets the statement to its initial condition. This includes any current
// result row, and also the bound variables if the |clear_bound_vars| is true.
void Reset(bool clear_bound_vars);
// Returns true if the last executed thing in this statement succeeded. If
// there was no last executed thing or the statement is invalid, this will
// return false.
bool Succeeded() const;
// Binding -------------------------------------------------------------------
// These all take a 0-based parameter index and return true on success.
// strings there may be out of memory.
void BindNull(int param_index);
void BindBool(int param_index, bool val);
void BindInt(int param_index, int val);
void BindInt(int param_index,
int64_t val) = delete; // Call BindInt64() instead.
void BindInt64(int param_index, int64_t val);
void BindDouble(int param_index, double val);
void BindCString(int param_index, const char* val);
void BindString(int param_index, base::StringPiece val);
// If you need to store (potentially invalid) UTF-16 strings losslessly,
// store them as BLOBs instead. `BindBlob()` has an overload for this purpose.
void BindString16(int param_index, base::StringPiece16 value);
void BindBlob(int param_index, base::span<const uint8_t> value);
// Overload that makes it easy to pass in std::string values.
void BindBlob(int param_index, base::span<const char> value) {
BindBlob(param_index, base::as_bytes(base::make_span(value)));
}
// Overload that makes it easy to pass in std::u16string values.
void BindBlob(int param_index, base::span<const char16_t> value) {
BindBlob(param_index, base::as_bytes(base::make_span(value)));
}
// Conforms with base::Time serialization recommendations.
//
// This is equivalent to the following snippets, which should be replaced.
// * BindInt64(col, val.ToInternalValue())
// * BindInt64(col, val.ToDeltaSinceWindowsEpoch().InMicroseconds())
//
// Features that serialize base::Time in other ways, such as ToTimeT() or
// InMillisecondsSinceUnixEpoch(), will require a database migration to be
// converted to this (recommended) serialization method.
//
// TODO(crbug.com/1195962): Migrate all time serialization to this method, and
// then remove the migration details above.
void BindTime(int param_index, base::Time time);
// Conforms with base::TimeDelta serialization recommendations.
//
// This is equivalent to the following snippets, which should be replaced.
// * BindInt64(col, delta.ToInternalValue())
// * BindInt64(col, delta.InMicroseconds())
//
// TODO(crbug.com/1402777): Migrate all TimeDelta serialization to this method
// and remove the migration details above.
void BindTimeDelta(int param_index, base::TimeDelta delta);
// Retrieving ----------------------------------------------------------------
// Returns the number of output columns in the result.
int ColumnCount() const;
// Returns the type associated with the given column.
//
// Watch out: the type may be undefined if you've done something to cause a
// "type conversion." This means requesting the value of a column of a type
// where that type is not the native type. For safety, call ColumnType only
// on a column before getting the value out in any way.
ColumnType GetColumnType(int col);
// These all take a 0-based argument index.
bool ColumnBool(int column_index);
int ColumnInt(int column_index);
int64_t ColumnInt64(int column_index);
double ColumnDouble(int column_index);
std::string ColumnString(int column_index);
// If you need to store and retrieve (potentially invalid) UTF-16 strings
// losslessly, store them as BLOBs instead. They may be retrieved with
// `ColumnBlobAsString16()`.
std::u16string ColumnString16(int column_index);
// Conforms with base::Time serialization recommendations.
//
// This is equivalent to the following snippets, which should be replaced.
// * base::Time::FromInternalValue(ColumnInt64(col))
// * base::Time::FromDeltaSinceWindowsEpoch(
// base::Microseconds(ColumnInt64(col)))
//
// TODO(crbug.com/1195962): Migrate all time serialization to this method, and
// then remove the migration details above.
base::Time ColumnTime(int column_index);
// Conforms with base::TimeDelta deserialization recommendations.
//
// This is equivalent to the following snippets, which should be replaced.
// * base::TimeDelta::FromInternalValue(ColumnInt64(column_index))
//
// TODO(crbug.com/1402777): Migrate all TimeDelta serialization to this method
// and remove the migration details above.
base::TimeDelta ColumnTimeDelta(int column_index);
// Returns a span pointing to a buffer containing the blob data.
//
// The span's contents should be copied to a caller-owned buffer immediately.
// Any method call on the Statement may invalidate the span.
//
// The span will be empty (and may have a null data) if the underlying blob is
// empty. Code that needs to distinguish between empty blobs and NULL should
// call GetColumnType() before calling ColumnBlob().
base::span<const uint8_t> ColumnBlob(int column_index);
bool ColumnBlobAsString(int column_index, std::string* result);
bool ColumnBlobAsString16(int column_index, std::u16string* result);
bool ColumnBlobAsVector(int column_index, std::vector<char>* result);
bool ColumnBlobAsVector(int column_index, std::vector<uint8_t>* result);
// Diagnostics --------------------------------------------------------------
// Returns the original text of a SQL statement WITHOUT any bound values.
// Intended for logging in case of failures. Note that DOES NOT return any
// bound values, because that would cause a privacy / PII issue for logging.
std::string GetSQLStatement();
private:
friend class Database;
// Checks SQLite result codes and handles any errors.
//
// Returns `sqlite_result_code`. This gives callers the convenience of writing
// "return CheckSqliteResultCode(sqlite_result_code)" and gives the compiler
// the opportunity of doing tail call optimization (TCO) on the code above.
//
// This method reports error codes to the associated Database, and updates
// internal state to reflect whether the statement succeeded or not.
SqliteResultCode CheckSqliteResultCode(SqliteResultCode sqlite_result_code);
// Should be called by all mutating methods to check that the statement is
// valid. Returns true if the statement is valid. DCHECKS and returns false
// if it is not.
// The reason for this is to handle two specific cases in which a Statement
// may be invalid. The first case is that the programmer made an SQL error.
// Those cases need to be DCHECKed so that we are guaranteed to find them
// before release. The second case is that the computer has an error (probably
// out of disk space) which is prohibiting the correct operation of the
// database. Our testing apparatus should not exhibit this defect, but release
// situations may. Therefore, the code is handling disjoint situations in
// release and test. In test, we're ensuring correct SQL. In release, we're
// ensuring that contracts are honored in error edge cases.
bool CheckValid() const;
// Helper for Run() and Step(), calls sqlite3_step() and returns the checked
// value from it.
SqliteResultCode StepInternal();
// The actual sqlite statement. This may be unique to us, or it may be cached
// by the Database, which is why it's ref-counted. This pointer is
// guaranteed non-null.
scoped_refptr<Database::StatementRef> ref_
GUARDED_BY_CONTEXT(sequence_checker_);
// See Succeeded() for what this holds.
bool succeeded_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
#if DCHECK_IS_ON()
// Used to DCHECK() that Bind*() is called before Step() or Run() are called.
bool step_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
bool run_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
#endif // DCHECK_IS_ON()
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace sql
#endif // SQL_STATEMENT_H_