diff options
Diffstat (limited to 'src/components/utils/src/qdb_wrapper/sql_query.cc')
-rw-r--r-- | src/components/utils/src/qdb_wrapper/sql_query.cc | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/components/utils/src/qdb_wrapper/sql_query.cc b/src/components/utils/src/qdb_wrapper/sql_query.cc new file mode 100644 index 0000000000..e5facb5853 --- /dev/null +++ b/src/components/utils/src/qdb_wrapper/sql_query.cc @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qdb_wrapper/sql_query.h" +#include <string.h> +#include <cassert> +#include <algorithm> +#include "qdb_wrapper/sql_database.h" +#include "utils/logger.h" +#include <errno.h> + +namespace utils { +namespace dbms { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") + +class SetBindInteger { + public: + explicit SetBindInteger(qdb_binding_t* array) : array_(array) {} + void operator()(const std::pair<int, int64_t>& x) { + // In QDB the number of position for binding starts since 1. + QDB_SETARRAYBIND_INT(array_, x.first + 1, x.second); + } + + private: + qdb_binding_t* array_; +}; + +class SetBindReal { + public: + explicit SetBindReal(qdb_binding_t* array) : array_(array) {} + void operator()(const std::pair<int, double>& x) { + // In QDB the number of position for binding starts since 1. + QDB_SETARRAYBIND_REAL(array_, x.first + 1, x.second); + } + + private: + qdb_binding_t* array_; +}; + +class SetBindText { + public: + explicit SetBindText(qdb_binding_t* array) : array_(array) {} + void operator()(const std::pair<int, std::string>& x) { + // In QDB the number of position for binding starts since 1. + QDB_SETARRAYBIND_TEXT(array_, x.first + 1, x.second.c_str()); + } + + private: + qdb_binding_t* array_; +}; + +class SetBindNull { + public: + explicit SetBindNull(qdb_binding_t* array) : array_(array) {} + void operator()(int x) { + // In QDB the number of position for binding starts since 1. + QDB_SETARRAYBIND_NULL(array_, x + 1); + } + + private: + qdb_binding_t* array_; +}; + +SQLQuery::SQLQuery(SQLDatabase* db) + : db_(db) + , query_("") + , statement_(-1) + , bindings_(NULL) + , result_(NULL) + , current_row_(0) + , rows_(0) + , error_(Error::OK) {} + +SQLQuery::~SQLQuery() { + Finalize(); + db_->Close(); + delete db_; +} + +bool SQLQuery::Prepare(const std::string& query) { + query_ = query; + statement_ = qdb_stmt_init(db_->conn(), query.c_str(), query.length() + 1); + if (statement_ == -1) { + LOG4CXX_DEBUG(logger_, "Prepare error: " << strerror(errno)); + error_ = Error::ERROR; + return false; + } + return true; +} + +uint8_t SQLQuery::SetBinds() { + uint8_t binding_count = int_binds_.size() + double_binds_.size() + + string_binds_.size() + null_binds_.size(); + + bindings_ = new qdb_binding_t[binding_count]; + + std::for_each( + int_binds_.begin(), int_binds_.end(), SetBindInteger(bindings_)); + std::for_each( + double_binds_.begin(), double_binds_.end(), SetBindReal(bindings_)); + std::for_each( + string_binds_.begin(), string_binds_.end(), SetBindText(bindings_)); + std::for_each(null_binds_.begin(), null_binds_.end(), SetBindNull(bindings_)); + + return binding_count; +} + +bool SQLQuery::Result() { + result_ = qdb_getresult(db_->conn()); + if (!result_) { + error_ = Error::ERROR; + return false; + } + rows_ = qdb_rows(result_); + if (rows_ == -1) { + rows_ = 0; + error_ = Error::ERROR; + return false; + } + return true; +} + +bool SQLQuery::Exec() { + sync_primitives::AutoLock auto_lock(bindings_lock_); + if (result_) + return true; + + current_row_ = 0; + uint8_t binding_count = SetBinds(); + if (qdb_stmt_exec(db_->conn(), statement_, bindings_, binding_count) == -1) { + error_ = Error::ERROR; + return false; + } + return Result(); +} + +bool SQLQuery::Next() { + ++current_row_; + return Exec() && current_row_ < rows_; +} + +bool SQLQuery::Reset() { + sync_primitives::AutoLock auto_lock(bindings_lock_); + int_binds_.clear(); + double_binds_.clear(); + string_binds_.clear(); + null_binds_.clear(); + delete[] bindings_; + bindings_ = NULL; + rows_ = 0; + current_row_ = 0; + if (result_ && qdb_freeresult(result_) == -1) { + error_ = Error::ERROR; + return false; + } + result_ = NULL; + return true; +} + +void SQLQuery::Finalize() { + if (Reset() && qdb_stmt_free(db_->conn(), statement_) != -1) { + statement_ = 0; + } else { + error_ = Error::ERROR; + } +} + +bool SQLQuery::Exec(const std::string& query) { + query_ = query; + if (qdb_statement(db_->conn(), query.c_str()) == -1) { + error_ = Error::ERROR; + return false; + } + return true; +} + +void SQLQuery::Bind(int pos, int value) { + int_binds_.push_back(std::make_pair(pos, value)); +} + +void SQLQuery::Bind(int pos, int64_t value) { + int_binds_.push_back(std::make_pair(pos, value)); +} + +void SQLQuery::Bind(int pos, double value) { + double_binds_.push_back(std::make_pair(pos, value)); +} + +void SQLQuery::Bind(int pos, bool value) { + Bind(pos, static_cast<int>(value)); +} + +void SQLQuery::Bind(int pos, const std::string& value) { + string_binds_.push_back(std::make_pair(pos, value)); +} + +void SQLQuery::Bind(int pos) { + null_binds_.push_back(pos); +} + +bool SQLQuery::GetBoolean(int pos) const { + return static_cast<bool>(GetInteger(pos)); +} + +int SQLQuery::GetInteger(int pos) const { + void* ret = qdb_cell(result_, current_row_, pos); + if (rows_ != 0 && ret) { + return *static_cast<int*>(ret); + } + return 0; +} + +uint32_t SQLQuery::GetUInteger(int pos) const { + void* ret = qdb_cell(result_, current_row_, pos); + if (rows_ != 0 && ret) { + return *static_cast<uint32_t*>(ret); + } + return 0; +} + +int64_t SQLQuery::GetLongInt(int pos) const { + void* ret = qdb_cell(result_, current_row_, pos); + if (rows_ != 0 && ret) { + return *static_cast<int64_t*>(ret); + } + return 0; +} + +double SQLQuery::GetDouble(int pos) const { + void* ret = qdb_cell(result_, current_row_, pos); + if (rows_ != 0 && ret) { + return *static_cast<double*>(ret); + } + return 0; +} + +std::string SQLQuery::GetString(int pos) const { + void* ret = qdb_cell(result_, current_row_, pos); + if (rows_ != 0 && ret) { + return static_cast<const char*>(ret); + } + return ""; +} + +bool SQLQuery::IsNull(int pos) const { + return rows_ == 0 || qdb_cell_type(result_, current_row_, pos) == QDB_NULL; +} + +const std::string& SQLQuery::query() const { + // TODO(KKolodiy): may return string query with value of arguments + return query_; +} + +SQLError SQLQuery::LastError() const { + return SQLError(error_, qdb_geterrmsg(db_->conn())); +} + +int64_t SQLQuery::LastInsertId() const { + return qdb_last_insert_rowid(db_->conn(), result_); +} + +} // namespace dbms +} // namespace utils |