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