pull in new policy updates
[profile/ivi/smartdevicelink.git] / src / components / policy / src / policy / qdb_wrapper / src / sql_query.cc
1 /**
2  * Copyright (c) 2013, Ford Motor Company
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
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
14  * distribution.
15  *
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.
19  *
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.
31  */
32
33 #include "qdb_wrapper/sql_query.h"
34 #include <string.h>
35 #include <cassert>
36 #include <algorithm>
37 #include "qdb_wrapper/sql_database.h"
38
39 namespace policy {
40 namespace dbms {
41
42 class SetBindInteger {
43  public:
44   explicit SetBindInteger(qdb_binding_t* array)
45       : array_(array) {
46   }
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);
50   }
51  private:
52   qdb_binding_t* array_;
53 };
54
55 class SetBindReal {
56  public:
57   explicit SetBindReal(qdb_binding_t* array)
58       : array_(array) {
59   }
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));
64   }
65  private:
66   qdb_binding_t* array_;
67 };
68
69 class SetBindText {
70  public:
71   explicit SetBindText(qdb_binding_t* array)
72       : array_(array) {
73   }
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());
77   }
78  private:
79   qdb_binding_t* array_;
80 };
81
82 class SetBindNull {
83  public:
84   explicit SetBindNull(qdb_binding_t* array)
85       : array_(array) {
86   }
87   void operator()(int x) {
88     // In QDB the number of position for binding starts since 1.
89     QDB_SETARRAYBIND_NULL(array_, x + 1);
90   }
91  private:
92   qdb_binding_t* array_;
93 };
94
95 SQLQuery::SQLQuery(SQLDatabase* db)
96     : db_(db),
97       query_(""),
98       statement_(-1),
99       bindings_(NULL),
100       result_(NULL),
101       current_row_(0),
102       rows_(0),
103       error_(Error::OK) {
104 }
105
106 SQLQuery::~SQLQuery() {
107   Finalize();
108   db_->Close();
109   delete db_;
110 }
111
112 bool SQLQuery::Prepare(const std::string& query) {
113   query_ = query;
114   statement_ = qdb_stmt_init(db_->conn(), query.c_str(), query.length() + 1);
115   if (statement_ == -1) {
116     error_ = Error::ERROR;
117     return false;
118   }
119   return true;
120 }
121
122 int SQLQuery::SetBinds() {
123   int binding_count = int_binds_.size() + double_binds_.size()
124       + string_binds_.size() + null_binds_.size();
125
126   bindings_ = new qdb_binding_t[binding_count];
127
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_));
135
136   return binding_count;
137 }
138
139 bool SQLQuery::Result() {
140   result_ = qdb_getresult(db_->conn());
141   if (!result_) {
142     error_ = Error::ERROR;
143     return false;
144   }
145   rows_ = qdb_rows(result_);
146   if (rows_ == -1) {
147     rows_ = 0;
148     error_ = Error::ERROR;
149     return false;
150   }
151   return true;
152 }
153
154 bool SQLQuery::Exec() {
155   sync_primitives::AutoLock auto_lock(bindings_lock_);
156   if (result_)
157     return true;
158
159   current_row_ = 0;
160   int binding_count = SetBinds();
161   if (qdb_stmt_exec(db_->conn(), statement_, bindings_, binding_count) == -1) {
162     error_ = Error::ERROR;
163     return false;
164   }
165   return Result();
166 }
167
168 bool SQLQuery::Next() {
169   ++current_row_;
170   return Exec() && current_row_ < rows_;
171 }
172
173 bool SQLQuery::Reset() {
174   sync_primitives::AutoLock auto_lock(bindings_lock_);
175   int_binds_.clear();
176   double_binds_.clear();
177   string_binds_.clear();
178   null_binds_.clear();
179   delete[] bindings_;
180   bindings_ = NULL;
181   rows_ = 0;
182   current_row_ = 0;
183   if (result_ && qdb_freeresult(result_) == -1) {
184     error_ = Error::ERROR;
185     return false;
186   }
187   result_ = NULL;
188   return true;
189 }
190
191 void SQLQuery::Finalize() {
192   if (Reset() && qdb_stmt_free(db_->conn(), statement_) != -1) {
193     statement_ = 0;
194   } else {
195     error_ = Error::ERROR;
196   }
197 }
198
199 bool SQLQuery::Exec(const std::string& query) {
200   query_ = query;
201   if (qdb_statement(db_->conn(), query.c_str()) == -1) {
202     error_ = Error::ERROR;
203     return false;
204   }
205   return true;
206 }
207
208 void SQLQuery::Bind(int pos, int value) {
209   int_binds_.push_back(std::make_pair(pos, value));
210 }
211
212 void SQLQuery::Bind(int pos, int64_t value) {
213   int_binds_.push_back(std::make_pair(pos, value));
214 }
215
216 void SQLQuery::Bind(int pos, double value) {
217   double_binds_.push_back(std::make_pair(pos, value));
218 }
219
220 void SQLQuery::Bind(int pos, bool value) {
221   Bind(pos, static_cast<int>(value));
222 }
223
224 void SQLQuery::Bind(int pos, const std::string& value) {
225   string_binds_.push_back(std::make_pair(pos, value));
226 }
227
228 void SQLQuery::Bind(int pos) {
229   null_binds_.push_back(pos);
230 }
231
232 bool SQLQuery::GetBoolean(int pos) const {
233   return static_cast<bool>(GetInteger(pos));
234 }
235
236 int SQLQuery::GetInteger(int pos) const {
237   return rows_ == 0 ? 0 :
238       *static_cast<int*>(qdb_cell(result_, current_row_, pos));
239 }
240
241 double SQLQuery::GetDouble(int pos) const {
242   return rows_ == 0 ? 0 :
243       *static_cast<double*>(qdb_cell(result_, current_row_, pos));
244 }
245
246 std::string SQLQuery::GetString(int pos) const {
247   if (rows_ == 0) {
248     return "";
249   }
250   void* str = qdb_cell(result_, current_row_, pos);
251   return str ? static_cast<const char*>(str) : "";
252 }
253
254 bool SQLQuery::IsNull(int pos) const {
255   return rows_ == 0 || qdb_cell_type(result_, current_row_, pos) == QDB_NULL;
256 }
257
258 const std::string& SQLQuery::query() const {
259   // TODO(KKolodiy): may return string query with value of arguments
260   return query_;
261 }
262
263 SQLError SQLQuery::LastError() const {
264   return SQLError(error_, qdb_geterrmsg(db_->conn()));
265 }
266
267 int64_t SQLQuery::LastInsertId() const {
268   return qdb_last_insert_rowid(db_->conn(), result_);
269 }
270
271 }  // namespace dbms
272 }  // namespace policy
273