2 * Copyright (c) 2013, Ford Motor Company
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided with the
16 * Neither the name of the Ford Motor Company nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include "qdb_wrapper/sql_query.h"
37 #include "qdb_wrapper/sql_database.h"
42 class SetBindInteger {
44 explicit SetBindInteger(qdb_binding_t* array)
47 void operator()(const std::pair<int, int64_t>& x) {
48 // In QDB the number of position for binding starts since 1.
49 QDB_SETARRAYBIND_INT(array_, x.first + 1, x.second);
52 qdb_binding_t* array_;
57 explicit SetBindReal(qdb_binding_t* array)
60 void operator()(const std::pair<int, double>& x) {
61 // In QDB the number of position for binding starts since 1.
62 QDB_SETBIND(&(array_[x.first + 1]), x.first + 1, QDB_REAL,
63 (sizeof(x.second)), &(x.second));
66 qdb_binding_t* array_;
71 explicit SetBindText(qdb_binding_t* array)
74 void operator()(const std::pair<int, std::string>& x) {
75 // In QDB the number of position for binding starts since 1.
76 QDB_SETARRAYBIND_TEXT(array_, x.first + 1, x.second.c_str());
79 qdb_binding_t* array_;
84 explicit SetBindNull(qdb_binding_t* array)
87 void operator()(int x) {
88 // In QDB the number of position for binding starts since 1.
89 QDB_SETARRAYBIND_NULL(array_, x + 1);
92 qdb_binding_t* array_;
95 SQLQuery::SQLQuery(SQLDatabase* db)
106 SQLQuery::~SQLQuery() {
112 bool SQLQuery::Prepare(const std::string& query) {
114 statement_ = qdb_stmt_init(db_->conn(), query.c_str(), query.length() + 1);
115 if (statement_ == -1) {
116 error_ = Error::ERROR;
122 int SQLQuery::SetBinds() {
123 int binding_count = int_binds_.size() + double_binds_.size()
124 + string_binds_.size() + null_binds_.size();
126 bindings_ = new qdb_binding_t[binding_count];
128 std::for_each(int_binds_.begin(), int_binds_.end(),
129 SetBindInteger(bindings_));
130 std::for_each(double_binds_.begin(), double_binds_.end(),
131 SetBindReal(bindings_));
132 std::for_each(string_binds_.begin(), string_binds_.end(),
133 SetBindText(bindings_));
134 std::for_each(null_binds_.begin(), null_binds_.end(), SetBindNull(bindings_));
136 return binding_count;
139 bool SQLQuery::Result() {
140 result_ = qdb_getresult(db_->conn());
142 error_ = Error::ERROR;
145 rows_ = qdb_rows(result_);
148 error_ = Error::ERROR;
154 bool SQLQuery::Exec() {
155 sync_primitives::AutoLock auto_lock(bindings_lock_);
160 int binding_count = SetBinds();
161 if (qdb_stmt_exec(db_->conn(), statement_, bindings_, binding_count) == -1) {
162 error_ = Error::ERROR;
168 bool SQLQuery::Next() {
170 return Exec() && current_row_ < rows_;
173 bool SQLQuery::Reset() {
174 sync_primitives::AutoLock auto_lock(bindings_lock_);
176 double_binds_.clear();
177 string_binds_.clear();
183 if (result_ && qdb_freeresult(result_) == -1) {
184 error_ = Error::ERROR;
191 void SQLQuery::Finalize() {
192 if (Reset() && qdb_stmt_free(db_->conn(), statement_) != -1) {
195 error_ = Error::ERROR;
199 bool SQLQuery::Exec(const std::string& query) {
201 if (qdb_statement(db_->conn(), query.c_str()) == -1) {
202 error_ = Error::ERROR;
208 void SQLQuery::Bind(int pos, int value) {
209 int_binds_.push_back(std::make_pair(pos, value));
212 void SQLQuery::Bind(int pos, int64_t value) {
213 int_binds_.push_back(std::make_pair(pos, value));
216 void SQLQuery::Bind(int pos, double value) {
217 double_binds_.push_back(std::make_pair(pos, value));
220 void SQLQuery::Bind(int pos, bool value) {
221 Bind(pos, static_cast<int>(value));
224 void SQLQuery::Bind(int pos, const std::string& value) {
225 string_binds_.push_back(std::make_pair(pos, value));
228 void SQLQuery::Bind(int pos) {
229 null_binds_.push_back(pos);
232 bool SQLQuery::GetBoolean(int pos) const {
233 return static_cast<bool>(GetInteger(pos));
236 int SQLQuery::GetInteger(int pos) const {
237 return rows_ == 0 ? 0 :
238 *static_cast<int*>(qdb_cell(result_, current_row_, pos));
241 double SQLQuery::GetDouble(int pos) const {
242 return rows_ == 0 ? 0 :
243 *static_cast<double*>(qdb_cell(result_, current_row_, pos));
246 std::string SQLQuery::GetString(int pos) const {
250 void* str = qdb_cell(result_, current_row_, pos);
251 return str ? static_cast<const char*>(str) : "";
254 bool SQLQuery::IsNull(int pos) const {
255 return rows_ == 0 || qdb_cell_type(result_, current_row_, pos) == QDB_NULL;
258 const std::string& SQLQuery::query() const {
259 // TODO(KKolodiy): may return string query with value of arguments
263 SQLError SQLQuery::LastError() const {
264 return SQLError(error_, qdb_geterrmsg(db_->conn()));
267 int64_t SQLQuery::LastInsertId() const {
268 return qdb_last_insert_rowid(db_->conn(), result_);
272 } // namespace policy