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