backends/sqlite3/statement.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "soci-sqlite3.h"
8 // std
9 #include <algorithm>
10 #include <sstream>
11 #include <string>
12 
13 #ifdef _MSC_VER
14 #pragma warning(disable:4355)
15 #endif
16 
17 using namespace soci;
18 using namespace soci::details;
19 using namespace sqlite_api;
20 
23  : session_(session)
24  , stmt_(0)
25  , dataCache_()
26  , useData_(0)
27  , databaseReady_(false)
28  , boundByName_(false)
29  , boundByPos_(false)
30  , rowsAffectedBulk_(-1LL)
31 {
32 }
33 
35 {
36  // ...
37 }
38 
40 {
41  rowsAffectedBulk_ = -1LL;
42 
43  if (stmt_)
44  {
45  sqlite3_finalize(stmt_);
46  stmt_ = 0;
47  databaseReady_ = false;
48  }
49 }
50 
51 void sqlite3_statement_backend::prepare(std::string const & query,
52  statement_type /* eType */)
53 {
54  clean_up();
55 
56  char const* tail = 0; // unused;
57  int const res = sqlite3_prepare_v2(session_.conn_,
58  query.c_str(),
59  static_cast<int>(query.size()),
60  &stmt_,
61  &tail);
62  if (res != SQLITE_OK)
63  {
64  char const* zErrMsg = sqlite3_errmsg(session_.conn_);
65 
66  std::ostringstream ss;
67  ss << "sqlite3_statement_backend::prepare: "
68  << zErrMsg;
69  throw sqlite3_soci_error(ss.str(), res);
70  }
71  databaseReady_ = true;
72 }
73 
74 // sqlite3_reset needs to be called before a prepared statment can
75 // be executed a second time.
77 {
78  if (stmt_ && databaseReady_ == false)
79  {
80  int const res = sqlite3_reset(stmt_);
81  if (SQLITE_OK == res)
82  {
83  databaseReady_ = true;
84  }
85  }
86 }
87 
88 // This is used by bulk operations
91 {
93  int numCols = -1;
94  int i = 0;
95 
96  if (!databaseReady_)
97  {
98  retVal = ef_no_data;
99  }
100  else
101  {
102  // make the vector big enough to hold the data we need
103  dataCache_.resize(totalRows);
104 
105  for (i = 0; i < totalRows && databaseReady_; ++i)
106  {
107  int const res = sqlite3_step(stmt_);
108 
109  if (SQLITE_DONE == res)
110  {
111  databaseReady_ = false;
112  retVal = ef_no_data;
113  break;
114  }
115  else if (SQLITE_ROW == res)
116  {
117  // only need to set the number of columns once
118  if (-1 == numCols)
119  {
120  numCols = sqlite3_column_count(stmt_);
121  for (sqlite3_recordset::iterator it = dataCache_.begin(),
122  end = dataCache_.end(); it != end; ++it)
123  {
124  (*it).resize(numCols);
125  }
126  }
127  for (int c = 0; c < numCols; ++c)
128  {
129  char const* buf =
130  reinterpret_cast<char const*>(sqlite3_column_text(stmt_, c));
131  bool isNull = false;
132  if (0 == buf)
133  {
134  isNull = true;
135  buf = "";
136  }
137  dataCache_[i][c].data_ = buf;
138  dataCache_[i][c].isNull_ = isNull;
139  }
140  }
141  else
142  {
143  clean_up();
144  char const* zErrMsg = sqlite3_errmsg(session_.conn_);
145  std::ostringstream ss;
146  ss << "sqlite3_statement_backend::loadRS: "
147  << zErrMsg;
148  throw sqlite3_soci_error(ss.str(), res);
149  }
150  }
151  }
152  // if we read less than requested then shrink the vector
153  dataCache_.resize(i);
154 
155  return retVal;
156 }
157 
158 // This is used for non-bulk operations
161 {
163 
164  int const res = sqlite3_step(stmt_);
165 
166  if (SQLITE_DONE == res)
167  {
168  databaseReady_ = false;
169  retVal = ef_no_data;
170  }
171  else if (SQLITE_ROW == res)
172  {
173  }
174  else
175  {
176  clean_up();
177 
178  char const* zErrMsg = sqlite3_errmsg(session_.conn_);
179 
180  std::ostringstream ss;
181  ss << "sqlite3_statement_backend::loadOne: "
182  << zErrMsg;
183  throw sqlite3_soci_error(ss.str(), res);
184  }
185 
186  return retVal;
187 }
188 
189 // Execute statements once for every row of useData
192 {
194 
195  long long rowsAffectedBulkTemp = 0;
196 
197  int const rows = static_cast<int>(useData_.size());
198  for (int row = 0; row < rows; ++row)
199  {
200  sqlite3_reset(stmt_);
201 
202  int const totalPositions = static_cast<int>(useData_[0].size());
203  for (int pos = 1; pos <= totalPositions; ++pos)
204  {
205  int bindRes = SQLITE_OK;
206  const sqlite3_column& curCol = useData_[row][pos-1];
207  if (curCol.isNull_)
208  {
209  bindRes = sqlite3_bind_null(stmt_, pos);
210  }
211  else if (curCol.blobBuf_)
212  {
213  bindRes = sqlite3_bind_blob(stmt_, pos,
214  curCol.blobBuf_,
215  static_cast<int>(curCol.blobSize_),
216  SQLITE_STATIC);
217  }
218  else
219  {
220  bindRes = sqlite3_bind_text(stmt_, pos,
221  curCol.data_.c_str(),
222  static_cast<int>(curCol.data_.length()),
223  SQLITE_STATIC);
224  }
225 
226  if (SQLITE_OK != bindRes)
227  {
228  // preserve the number of rows affected so far.
229  rowsAffectedBulk_ = rowsAffectedBulkTemp;
230  throw sqlite3_soci_error("Failure to bind on bulk operations", bindRes);
231  }
232  }
233 
234  // Handle the case where there are both into and use elements
235  // in the same query and one of the into binds to a vector object.
236  if (1 == rows && number != rows)
237  {
238  return load_rowset(number);
239  }
240 
241  retVal = load_one(); //execute each bound line
242  rowsAffectedBulkTemp += get_affected_rows();
243  }
244  rowsAffectedBulk_ = rowsAffectedBulkTemp;
245  return retVal;
246 }
247 
250 {
251  if (stmt_ == NULL)
252  {
253  throw soci_error("No sqlite statement created");
254  }
255 
256  sqlite3_reset(stmt_);
257  databaseReady_ = true;
258 
260 
261  if (useData_.empty() == false)
262  {
263  retVal = bind_and_execute(number);
264  }
265  else
266  {
267  if (1 == number)
268  {
269  retVal = load_one();
270  }
271  else
272  {
273  retVal = load_rowset(number);
274  }
275  }
276 
277  return retVal;
278 }
279 
282 {
283  return load_rowset(number);
284 }
285 
287 {
288  if (rowsAffectedBulk_ >= 0)
289  {
290  return rowsAffectedBulk_;
291  }
292  return sqlite3_changes(session_.conn_);
293 }
294 
296 {
297  return static_cast<int>(dataCache_.size());
298 }
299 
301  std::string const &query)
302 {
303  return query;
304 }
305 
307 {
308  return sqlite3_column_count(stmt_);
309 }
310 
312  std::string & columnName)
313 {
314  columnName = sqlite3_column_name(stmt_, colNum-1);
315 
316  // This is a hack, but the sqlite3 type system does not
317  // have a date or time field. Also it does not reliably
318  // id other data types. It has a tendency to see everything
319  // as text. sqlite3_column_decltype returns the text that is
320  // used in the create table statement
321  bool typeFound = false;
322 
323  char const* declType = sqlite3_column_decltype(stmt_, colNum-1);
324 
325  if ( declType == NULL )
326  {
327  static char const* s_char = "char";
328  declType = s_char;
329  }
330 
331  std::string dt = declType;
332 
333  // do all comparisons in lower case
334  std::transform(dt.begin(), dt.end(), dt.begin(), tolower);
335 
336  if (dt.find("time", 0) != std::string::npos)
337  {
338  type = dt_date;
339  typeFound = true;
340  }
341  if (dt.find("date", 0) != std::string::npos)
342  {
343  type = dt_date;
344  typeFound = true;
345  }
346 
347  if (dt.find("int8", 0) != std::string::npos || dt.find("bigint", 0) != std::string::npos)
348  {
349  type = dt_long_long;
350  typeFound = true;
351  }
352  else if (dt.find("unsigned big int", 0) != std::string::npos)
353  {
354  type = dt_unsigned_long_long;
355  typeFound = true;
356  }
357  else if (dt.find("int", 0) != std::string::npos)
358  {
359  type = dt_integer;
360  typeFound = true;
361  }
362 
363  if (dt.find("float", 0) != std::string::npos || dt.find("double", 0) != std::string::npos)
364  {
365  type = dt_double;
366  typeFound = true;
367  }
368  if (dt.find("text", 0) != std::string::npos)
369  {
370  type = dt_string;
371  typeFound = true;
372  }
373  if (dt.find("char", 0) != std::string::npos)
374  {
375  type = dt_string;
376  typeFound = true;
377  }
378  if (dt.find("boolean", 0) != std::string::npos)
379  {
380  type = dt_integer;
381  typeFound = true;
382  }
383 
384  if (typeFound)
385  {
386  return;
387  }
388 
389  // try to get it from the weak ass type system
390 
391  // total hack - execute the statment once to get the column types
392  // then clear so it can be executed again
393  sqlite3_step(stmt_);
394 
395  int const sqlite3_type = sqlite3_column_type(stmt_, colNum-1);
396  switch (sqlite3_type)
397  {
398  case SQLITE_INTEGER:
399  type = dt_integer;
400  break;
401  case SQLITE_FLOAT:
402  type = dt_double;
403  break;
404  case SQLITE_BLOB:
405  case SQLITE_TEXT:
406  type = dt_string;
407  break;
408  default:
409  type = dt_string;
410  break;
411  }
412 
413  sqlite3_reset(stmt_);
414 }
415 
418 {
419  return new sqlite3_standard_into_type_backend(*this);
420 }
421 
423 {
424  return new sqlite3_standard_use_type_backend(*this);
425 }
426 
429 {
430  return new sqlite3_vector_into_type_backend(*this);
431 }
432 
435 {
436  return new sqlite3_vector_use_type_backend(*this);
437 }
exec_fetch_result load_rowset(int totalRows)
sqlite3_statement_backend(sqlite3_session_backend &session)
virtual void describe_column(int colNum, data_type &dtype, std::string &columnName)
Definition: row.h:41
virtual sqlite3_vector_use_type_backend * make_vector_use_type_backend()
virtual exec_fetch_result fetch(int number)
virtual sqlite3_standard_into_type_backend * make_into_type_backend()
virtual sqlite3_vector_into_type_backend * make_vector_into_type_backend()
std::size_t blobSize_
Definition: soci-sqlite3.h:167
virtual exec_fetch_result execute(int number)
virtual sqlite3_standard_use_type_backend * make_use_type_backend()
#define SQLITE_STATIC
Definition: soci-sqlite3.h:50
virtual std::string rewrite_for_procedure_call(std::string const &query)
sqlite_api::sqlite3_stmt * stmt_
Definition: soci-sqlite3.h:202
virtual void prepare(std::string const &query, details::statement_type eType)
sqlite3_session_backend & session_
Definition: soci-sqlite3.h:201
sqlite_api::sqlite3 * conn_
Definition: soci-sqlite3.h:267
exec_fetch_result bind_and_execute(int number)


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:41