blob: 6da60611769f04b13a70d75303eb94efe0fe0626 [file] [log] [blame]
David Ghandehari9e5b5872016-07-28 09:50:04 -07001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Andrew Top61a84952019-04-30 15:07:33 -07005#if defined(STARBOARD)
6#include "starboard/client_porting/poem/string_leaks_poem.h"
7#endif // defined(STARBOARD)
8
David Ghandehari9e5b5872016-07-28 09:50:04 -07009#include "sql/statement.h"
10
11#include "base/logging.h"
Andrew Top0d1858f2019-05-15 22:01:47 -070012#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
David Ghandehari9e5b5872016-07-28 09:50:04 -070014#include "third_party/sqlite/sqlite3.h"
15
16namespace sql {
17
18// This empty constructor initializes our reference with an empty one so that
19// we don't have to NULL-check the ref_ to see if the statement is valid: we
20// only have to check the ref's validity bit.
21Statement::Statement()
22 : ref_(new Connection::StatementRef),
23 succeeded_(false) {
24}
25
26Statement::Statement(scoped_refptr<Connection::StatementRef> ref)
27 : ref_(ref),
28 succeeded_(false) {
29}
30
31Statement::~Statement() {
32 // Free the resources associated with this statement. We assume there's only
33 // one statement active for a given sqlite3_stmt at any time, so this won't
34 // mess with anything.
35 Reset(true);
36}
37
38void Statement::Assign(scoped_refptr<Connection::StatementRef> ref) {
39 Reset(true);
40 ref_ = ref;
41}
42
43void Statement::Clear() {
44 Assign(new Connection::StatementRef);
45 succeeded_ = false;
46}
47
48bool Statement::CheckValid() const {
49 if (!is_valid())
50 DLOG(FATAL) << "Cannot call mutating statements on an invalid statement.";
51 return is_valid();
52}
53
54bool Statement::Run() {
55 ref_->AssertIOAllowed();
56 if (!CheckValid())
57 return false;
58
59 return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_DONE;
60}
61
62bool Statement::Step() {
63 ref_->AssertIOAllowed();
64 if (!CheckValid())
65 return false;
66
67 return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_ROW;
68}
69
70void Statement::Reset(bool clear_bound_vars) {
71 ref_->AssertIOAllowed();
72 if (is_valid()) {
73 // We don't call CheckError() here because sqlite3_reset() returns
74 // the last error that Step() caused thereby generating a second
75 // spurious error callback.
76 if (clear_bound_vars)
77 sqlite3_clear_bindings(ref_->stmt());
78 sqlite3_reset(ref_->stmt());
79 }
80
81 succeeded_ = false;
82}
83
84bool Statement::Succeeded() const {
85 if (!is_valid())
86 return false;
87
88 return succeeded_;
89}
90
91bool Statement::BindNull(int col) {
92 if (!is_valid())
93 return false;
94
95 return CheckOk(sqlite3_bind_null(ref_->stmt(), col + 1));
96}
97
98bool Statement::BindBool(int col, bool val) {
99 return BindInt(col, val ? 1 : 0);
100}
101
102bool Statement::BindInt(int col, int val) {
103 if (!is_valid())
104 return false;
105
106 return CheckOk(sqlite3_bind_int(ref_->stmt(), col + 1, val));
107}
108
109bool Statement::BindInt64(int col, int64 val) {
110 if (!is_valid())
111 return false;
112
113 return CheckOk(sqlite3_bind_int64(ref_->stmt(), col + 1, val));
114}
115
116bool Statement::BindDouble(int col, double val) {
117 if (!is_valid())
118 return false;
119
120 return CheckOk(sqlite3_bind_double(ref_->stmt(), col + 1, val));
121}
122
123bool Statement::BindCString(int col, const char* val) {
124 if (!is_valid())
125 return false;
126
127 return CheckOk(
128 sqlite3_bind_text(ref_->stmt(), col + 1, val, -1, SQLITE_TRANSIENT));
129}
130
131bool Statement::BindString(int col, const std::string& val) {
132 if (!is_valid())
133 return false;
134
135 return CheckOk(sqlite3_bind_text(ref_->stmt(),
136 col + 1,
137 val.data(),
138 val.size(),
139 SQLITE_TRANSIENT));
140}
141
Andrew Top0d1858f2019-05-15 22:01:47 -0700142bool Statement::BindString16(int col, const base::string16& value) {
143 return BindString(col, base::UTF16ToUTF8(value));
David Ghandehari9e5b5872016-07-28 09:50:04 -0700144}
145
146bool Statement::BindBlob(int col, const void* val, int val_len) {
147 if (!is_valid())
148 return false;
149
150 return CheckOk(
151 sqlite3_bind_blob(ref_->stmt(), col + 1, val, val_len, SQLITE_TRANSIENT));
152}
153
154int Statement::ColumnCount() const {
155 if (!is_valid())
156 return 0;
157
158 return sqlite3_column_count(ref_->stmt());
159}
160
161ColType Statement::ColumnType(int col) const {
162 // Verify that our enum matches sqlite's values.
163 COMPILE_ASSERT(COLUMN_TYPE_INTEGER == SQLITE_INTEGER, integer_no_match);
164 COMPILE_ASSERT(COLUMN_TYPE_FLOAT == SQLITE_FLOAT, float_no_match);
165 COMPILE_ASSERT(COLUMN_TYPE_TEXT == SQLITE_TEXT, integer_no_match);
166 COMPILE_ASSERT(COLUMN_TYPE_BLOB == SQLITE_BLOB, blob_no_match);
167 COMPILE_ASSERT(COLUMN_TYPE_NULL == SQLITE_NULL, null_no_match);
168
169 return static_cast<ColType>(sqlite3_column_type(ref_->stmt(), col));
170}
171
172ColType Statement::DeclaredColumnType(int col) const {
173 std::string column_type(sqlite3_column_decltype(ref_->stmt(), col));
Andrew Top0d1858f2019-05-15 22:01:47 -0700174 base::ToLowerASCII(base::StringPiece(column_type));
David Ghandehari9e5b5872016-07-28 09:50:04 -0700175
176 if (column_type == "integer")
177 return COLUMN_TYPE_INTEGER;
178 else if (column_type == "float")
179 return COLUMN_TYPE_FLOAT;
180 else if (column_type == "text")
181 return COLUMN_TYPE_TEXT;
182 else if (column_type == "blob")
183 return COLUMN_TYPE_BLOB;
184
185 return COLUMN_TYPE_NULL;
186}
187
188std::string Statement::ColumnName(int col) const {
189 const char *name = sqlite3_column_name(ref_->stmt(), col);
190 std::string result;
191 if (name)
192 result.assign(name);
193 return result;
194}
195
196bool Statement::ColumnBool(int col) const {
197 return !!ColumnInt(col);
198}
199
200int Statement::ColumnInt(int col) const {
201 if (!CheckValid())
202 return 0;
203
204 return sqlite3_column_int(ref_->stmt(), col);
205}
206
207int64 Statement::ColumnInt64(int col) const {
208 if (!CheckValid())
209 return 0;
210
211 return sqlite3_column_int64(ref_->stmt(), col);
212}
213
214double Statement::ColumnDouble(int col) const {
215 if (!CheckValid())
216 return 0;
217
218 return sqlite3_column_double(ref_->stmt(), col);
219}
220
221std::string Statement::ColumnString(int col) const {
222 if (!CheckValid())
223 return "";
224
225 const char* str = reinterpret_cast<const char*>(
226 sqlite3_column_text(ref_->stmt(), col));
227 int len = sqlite3_column_bytes(ref_->stmt(), col);
228
229 std::string result;
230 if (str && len > 0)
231 result.assign(str, len);
232 return result;
233}
234
Andrew Top0d1858f2019-05-15 22:01:47 -0700235base::string16 Statement::ColumnString16(int col) const {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700236 if (!CheckValid())
Andrew Top0d1858f2019-05-15 22:01:47 -0700237 return base::string16();
David Ghandehari9e5b5872016-07-28 09:50:04 -0700238
239 std::string s = ColumnString(col);
Andrew Top0d1858f2019-05-15 22:01:47 -0700240 return !s.empty() ? base::UTF8ToUTF16(s) : base::string16();
David Ghandehari9e5b5872016-07-28 09:50:04 -0700241}
242
243int Statement::ColumnByteLength(int col) const {
244 if (!CheckValid())
245 return 0;
246
247 return sqlite3_column_bytes(ref_->stmt(), col);
248}
249
250const void* Statement::ColumnBlob(int col) const {
251 if (!CheckValid())
252 return NULL;
253
254 return sqlite3_column_blob(ref_->stmt(), col);
255}
256
257bool Statement::ColumnBlobAsString(int col, std::string* blob) {
258 if (!CheckValid())
259 return false;
260
261 const void* p = ColumnBlob(col);
262 size_t len = ColumnByteLength(col);
263 blob->resize(len);
264 if (blob->size() != len) {
265 return false;
266 }
267 blob->assign(reinterpret_cast<const char*>(p), len);
268 return true;
269}
270
Andrew Top0d1858f2019-05-15 22:01:47 -0700271bool Statement::ColumnBlobAsString16(int col, base::string16* val) const {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700272 if (!CheckValid())
273 return false;
274
275 const void* data = ColumnBlob(col);
Andrew Top0d1858f2019-05-15 22:01:47 -0700276 size_t len = ColumnByteLength(col) / sizeof(base::char16);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700277 val->resize(len);
278 if (val->size() != len)
279 return false;
Andrew Top0d1858f2019-05-15 22:01:47 -0700280 val->assign(reinterpret_cast<const base::char16*>(data), len);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700281 return true;
282}
283
284bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const {
285 val->clear();
286
287 if (!CheckValid())
288 return false;
289
290 const void* data = sqlite3_column_blob(ref_->stmt(), col);
291 int len = sqlite3_column_bytes(ref_->stmt(), col);
292 if (data && len > 0) {
293 val->resize(len);
294 memcpy(&(*val)[0], data, len);
295 }
296 return true;
297}
298
299bool Statement::ColumnBlobAsVector(
300 int col,
301 std::vector<unsigned char>* val) const {
302 return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val));
303}
304
305const char* Statement::GetSQLStatement() {
306 return sqlite3_sql(ref_->stmt());
307}
308
309bool Statement::CheckOk(int err) const {
310 // Binding to a non-existent variable is evidence of a serious error.
311 // TODO(gbillock,shess): make this invalidate the statement so it
312 // can't wreak havoc.
313 if (err == SQLITE_RANGE)
314 DLOG(FATAL) << "Bind value out of range";
315 return err == SQLITE_OK;
316}
317
318int Statement::CheckError(int err) {
319 // Please don't add DCHECKs here, OnSqliteError() already has them.
320 succeeded_ = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
321 if (!succeeded_ && is_valid())
322 return ref_->connection()->OnSqliteError(err, this);
323 return err;
324}
325
326} // namespace sql