SQLiteXX  0.1.0
 All Classes Namespaces Files Functions Enumerations Enumerator
Statement.h
Go to the documentation of this file.
1 
3 #ifndef __SQLITEXX_SQLITE_STATEMENT_H__
4 #define __SQLITEXX_SQLITE_STATEMENT_H__
5 
6 #include "Blob.h"
7 #include "DBConnection.h"
8 #include "SQLiteEnums.h"
9 #include "Value.h"
10 
11 #include <sqlite3.h>
12 
13 #include <cassert>
14 #include <cstring>
15 #include <functional>
16 #include <iostream>
17 #include <map>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 #include <limits.h>
23 
24 namespace sqlite
25 {
29  template <typename T>
30  class reader
31  {
32  public:
33 
34  virtual ~reader() = default;
35 
40  int get_int(const int column) const noexcept
41  {
42  return sqlite3_column_int(static_cast<T const *>(this)->handle(), column);
43  }
44 
49  int get_int(const std::string& name) const noexcept
50  {
51  const int column = get_column_index(name);
52  return get_int(column);
53  }
54 
59  int64_t get_int64(const int column) const noexcept
60  {
61  return sqlite3_column_int64(static_cast<T const *>(this)->handle(), column);
62  }
63 
68  int64_t get_int64(const std::string& name) const noexcept
69  {
70  const int column = get_column_index(name);
71  return get_int64(column);
72  }
73 
78  unsigned int get_uint(const int column) const noexcept
79  {
80  return static_cast<unsigned int>(get_int64(column));
81  }
82 
87  unsigned int get_uint(const std::string& name) const noexcept
88  {
89  const int column = get_column_index(name);
90  return get_uint(column);
91  }
92 
97  double get_double(const int column) const noexcept
98  {
99  return sqlite3_column_double(static_cast<T const *>(this)->handle(), column);
100  }
101 
106  double get_double(const std::string& name) const noexcept
107  {
108  const int column = get_column_index(name);
109  return get_double(column);
110  }
111 
116  const blob get_blob(const int column) const noexcept
117  {
118  const void *blob = sqlite3_column_blob(static_cast<T const *>(this)->handle(), column);
119  return sqlite::blob(blob, get_bytes(column));
120  }
121 
126  const blob get_blob(const std::string& name) const noexcept
127  {
128  const int column = get_column_index(name);
129  return get_blob(column);
130  }
131 
136  const std::string get_string(const int column) const noexcept
137  {
138  const char *txt = get_text(column);
139  return std::string(txt, get_text_length(column));
140  }
141 
146  const std::string get_string(const std::string& name) const noexcept
147  {
148  const int column = get_column_index(name);
149  return get_string(column);
150  }
151 
156  const std::u16string get_u16string(const int column) const noexcept
157  {
158  const char16_t *txt = get_text16(column);
159  return std::u16string(txt, get_text16_length(column));
160  }
161 
166  const std::u16string get_u16string(const std::string& name) const noexcept
167  {
168  const int column = get_column_index(name);
169  return get_u16string(column);
170  }
171 
176  value get_value(const int column) const noexcept
177  {
178  return value(sqlite3_column_value(static_cast<T const *>(this)->handle(), column));
179  }
180 
185  value get_value(const std::string& name) const
186  {
187  const int column = get_column_index(name);
188  return get_value(column);
189  }
190 
191 
196  int get_bytes(const int column) const noexcept
197  {
198  return sqlite3_column_bytes(static_cast<T const *>(this)->handle(), column);
199  }
200 
205  int get_bytes(const std::string& name) const noexcept
206  {
207  const int column = get_column_index(name);
208  return get_bytes(column);
209  }
210 
215  datatype get_type(const int column) const noexcept
216  {
217  return static_cast<datatype>(sqlite3_column_type(static_cast<T const *>(this)->handle(), column));
218  }
219 
224  datatype get_type(const std::string& name) const noexcept
225  {
226  const int column = get_column_index(name);
227  return get_type(column);
228  }
229 
234  int column_count() const noexcept
235  {
236  return sqlite3_column_count(static_cast<T const *>(this)->handle());
237  }
238 
243  const char* get_column_name(const int index) const noexcept
244  {
245  return sqlite3_column_name(static_cast<T const *>(this)->handle(), index);
246  }
247 
252  const char16_t* get_column_wide_name(const int index) const noexcept
253  {
254  return sqlite3_column_name16(static_cast<T const *>(this)->handle(), index);
255  }
256 
261  int get_column_index(const std::string& name) const
262  {
263  std::map<std::string, int> columnNamesToIndex;
264 
265  const int columnCount = column_count();
266  for (int i = 0; i < columnCount; ++i) {
267  const char* columnName = sqlite3_column_name(static_cast<T const *>(this)->handle(), i);
268  columnNamesToIndex[columnName] = i;
269  }
270 
271  const std::map<std::string, int>::const_iterator index = columnNamesToIndex.find(name);
272  if (index == columnNamesToIndex.end())
273  {
274  throw SQLiteXXException("No column was found with that name");
275  }
276  return index->second;
277  }
278 
279  private:
280 
281  const char* get_text(const int column) const noexcept
282  {
283  return reinterpret_cast<char const *>(sqlite3_column_text(
284  static_cast<T const *>(this)->handle(), column));
285  }
286 
287  const char16_t* get_text16(const int column) const noexcept
288  {
289  return reinterpret_cast<char16_t const *>(sqlite3_column_text16(
290  static_cast<T const *>(this)->handle(), column));
291  }
292 
293  int get_text_length(const int column) const noexcept
294  {
295  return sqlite3_column_bytes(static_cast<T const *>(this)->handle(), column);
296  }
297 
298  int get_text16_length(const int column) const noexcept
299  {
300  return sqlite3_column_bytes16(static_cast<T const *>(this)->handle(), column) / sizeof(char16_t);
301  }
302  };
303 
304 
307  class row : public reader<row>
308  {
309  public:
310 
313  row(sqlite3_stmt* const statement) noexcept :
314  m_statement(statement)
315  {}
316 
319  sqlite3_stmt* handle() const noexcept
320  {
321  return m_statement;
322  }
323 
328  value operator[](int column) const
329  {
330  return get_value(column);
331  }
332 
337  value operator[](const std::string& name) const
338  {
339  return get_value(name);
340  }
341 
342  private:
343  sqlite3_stmt* m_statement = nullptr;
344  };
345 
346 
350  class statement : public reader<statement>
351  {
352  public:
356  statement() noexcept;
357 
363  template <typename ... Values>
365  const dbconnection& connection,
366  const std::string& text,
367  Values&& ... values) :
368  m_handle(nullptr, sqlite3_finalize),
369  m_done(false)
370  {
371  prepare(connection, text, std::forward<Values>(values) ...);
372  }
373 
380  template <typename ... Values>
382  const dbconnection& connection,
383  const std::u16string& text,
384  Values&& ... values) :
385  m_handle(nullptr, sqlite3_finalize),
386  m_done(false)
387  {
388  prepare(connection, text, std::forward<Values>(values) ...);
389  }
390 
394  operator bool() const noexcept;
395 
400  sqlite3_stmt* handle() const noexcept;
401 
407  template <typename ... Values>
408  void prepare(
409  dbconnection const& connection,
410  const std::string& text,
411  Values&& ... values)
412  {
413  internal_prepare(connection, sqlite3_prepare_v2, text.c_str(), std::forward<Values>(values) ...);
414  }
415 
421  template <typename ... Values>
422  void prepare(
423  const dbconnection& connection,
424  const std::u16string& text,
425  Values&& ... values)
426  {
427  internal_prepare(connection, sqlite3_prepare16_v2, text.c_str(), std::forward<Values>(values) ...);
428  }
429 
435  bool step() const;
436 
440  int execute() const;
441 
446  void bind(const int index, const int value) const;
447 
452  void bind(const int index, const double value) const;
453 
460  void bind(const int index, const void* const value, const int size, bindtype type = bindtype::transiently) const;
461 
466  void bind(const int index, const blob& value) const;
467 
474  void bind(const int index, const char* const value, const int size = -1, bindtype type = bindtype::transiently) const;
475 
482  void bind(const int index, const char16_t* const value, const int size = -1, bindtype type = bindtype::transiently) const;
483 
488  void bind(const int index, const std::string& value) const;
489 
494  void bind(const int index, const std::u16string& value) const;
495 
500  template <typename T>
501  void bind_name(const std::string& name, T&& value)
502  {
503  const int index = sqlite3_bind_parameter_index(handle(), name.c_str());
504  bind(index, value);
505  }
506 
510  template <typename ... Values>
511  void bind_all(Values&& ... values) const
512  {
513  internal_bind(1, std::forward<Values>(values) ...);
514  }
515 
519  template <typename ... Values>
520  void clear_bindings(Values&& ... values) const
521  {
522  if (SQLITE_OK != sqlite3_clear_bindings(handle()))
523  {
524  throw_last_error();
525  }
526 
527  bind_all(values ...);
528  }
529 
530 
535  void reset() const
536  {
537  if (SQLITE_OK != sqlite3_reset(handle()))
538  {
539  throw_last_error();
540  }
541  m_done = false;
542  }
543 
544  private:
545  using statement_handle = std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)>;
546  statement_handle m_handle;
547 
548  mutable bool m_done;
549 
550  template <typename F, typename C, typename ... Values>
551  void internal_prepare(
552  const dbconnection& connection,
553  F prepare,
554  const C * const text,
555  Values&& ... values)
556  {
557  assert(connection);
558 
559  sqlite3_stmt *statement;
560  if (SQLITE_OK != prepare(connection.handle(), text, -1, &statement, nullptr))
561  {
562  const int errcode = sqlite3_extended_errcode(connection.handle());
563  const std::string message = sqlite3_errmsg(connection.handle());
564  sqlite3_finalize(statement);
565  throw_error_code(errcode, message);
566  }
567 
568  m_handle.reset(statement);
569  bind_all(std::forward<Values>(values) ...);
570  }
571 
572  void internal_bind(int) const noexcept
573  {}
574 
575  template <typename First, typename ... Rest>
576  void internal_bind(const int index, First&& first, Rest&& ... rest) const
577  {
578  bind(index, std::forward<First>(first));
579  internal_bind(index + 1, std::forward<Rest>(rest) ...);
580  }
581 
582  void throw_last_error() const;
583 
584  statement(const statement& other) = delete;
585  statement& operator=(statement& other) = delete;
586 
587  };
588 
593  {
594  public:
597  row_iterator() noexcept = default;
598 
603  row_iterator(const statement& statement) noexcept;
604 
607  row_iterator& operator++() noexcept;
608 
611  bool operator!=(const row_iterator& other) const noexcept;
612 
616  row operator*() const noexcept;
617 
618  private:
619  const statement* m_statement = nullptr;
620 
621  };
622 
627  row_iterator begin(const statement& statement) noexcept;
628 
633  row_iterator end(const statement& statement) noexcept;
634 
641  template <typename ... Values>
642  inline int execute(
643  const dbconnection& connection,
644  const std::string& text,
645  Values&& ... values)
646  {
647  return statement(connection, text.c_str(), std::forward<Values>(values) ...).execute();
648  }
649 
656  template <typename ... Values>
657  inline int execute(
658  const dbconnection& connection,
659  const std::u16string& text,
660  Values&& ... values)
661  {
662  return statement(connection, text.c_str(), std::forward<Values>(values) ...).execute();
663  }
664 
665  template <typename Call>
666  inline int internal_execute_callback(
667  void *data,
668  int numColumns,
669  char **colData,
670  char **colNames)
671  {
672  Call *userCallback = static_cast<Call *>(data);
673 
674  std::vector<std::string> columnData;
675  std::vector<std::string> columnName;
676  for (int i = 0; i < numColumns; i++) {
677  columnData.push_back(colData[i]? colData[i]: "");
678  columnName.push_back(colNames[i]? colNames[i]: "");
679  }
680 
681  (*userCallback)(columnData, columnName);
682  return 0;
683  }
684 
685  template <typename F, typename ... Args>
686  inline void execute_callback(
687  const dbconnection& connection,
688  const std::string& sql,
689  F&& callback,
690  Args&& ... args)
691  {
692  // TODO: Decide whether to go with lambda or with bind.
693  // Using variadic templates in a lambda requires C++14 but could be more performant.
694  // auto userCallback = [&](const std::vector<std::string> &colValues, const std::vector<std::string> &colNames) {
695  // callback(colValues, colNames, std::forward<Args>(args)...);
696  // };
697 
698  auto userCallback =
699  std::bind(
700  std::forward<F>(callback),
701  std::placeholders::_1,
702  std::placeholders::_2,
703  std::forward<Args>(args)...);
704 
705  typedef decltype(userCallback) Call;
706 
707  char *errmsgPtr = nullptr;
708  sqlite3_exec(connection.handle(), sql.c_str(), internal_execute_callback<Call>, (void *)&userCallback, nullptr);
709  delete errmsgPtr;
710 
711  throw_error_code(connection.handle());
712  }
713 }
714 
715 #endif
const std::u16string get_u16string(const int column) const noexcept
Returns the specified column value as a UTF-16 string.
Definition: Statement.h:156
Base class used to help with reading "sqlite3_stmt" information.
Definition: Statement.h:30
sqlite3 * handle() const noexcept
Returns pointer to the underlying "sqlite3" object.
row operator*() const noexcept
Dereference operation.
Definition: Statement.cpp:154
A SQLite dynamically typed value object, aka "sqlite3_value".
Definition: Value.h:27
unsigned int get_uint(const std::string &name) const noexcept
Returns the specified column value as an unsigned integer.
Definition: Statement.h:87
const std::u16string get_u16string(const std::string &name) const noexcept
Returns the specified column value as a UTF-16 string.
Definition: Statement.h:166
void prepare(const dbconnection &connection, const std::u16string &text, Values &&...values)
Turn an SQL query into byte code.
Definition: Statement.h:422
bool operator!=(const row_iterator &other) const noexcept
Comparison operation.
Definition: Statement.cpp:149
int execute(const dbconnection &connection, const std::string &text, Values &&...values)
Executes an SQL query on a database connection.
Definition: Statement.h:642
const char16_t * get_column_wide_name(const int index) const noexcept
Returns the name assigned to a particular column.
Definition: Statement.h:252
void bind_name(const std::string &name, T &&value)
Binds an value to a parameter in an SQL prepared statement.
Definition: Statement.h:501
means that the content will likely change in the near future and that SQLite should make its own priv...
const blob get_blob(const int column) const noexcept
Returns the specified column value as a blob object.
Definition: Statement.h:116
bool step() const
Evaluates a prepared statement.
Definition: Statement.cpp:37
unsigned int get_uint(const int column) const noexcept
Returns the specified column value as an unsigned integer.
Definition: Statement.h:78
const char * get_column_name(const int index) const noexcept
Returns the name assigned to a particular column.
Definition: Statement.h:243
int get_column_index(const std::string &name) const
Returns the position of a column with the specified name.
Definition: Statement.h:261
value get_value(const int column) const noexcept
Returns the specified column value as a value object.
Definition: Statement.h:176
a group and bits
statement(const dbconnection &connection, const std::u16string &text, Values &&...values)
Creates, prepares, and binds values into an SQL statement.
Definition: Statement.h:381
void bind(const int index, const int value) const
Binds an integer value to a parameter in an SQL prepared statement.
Definition: Statement.cpp:68
datatype get_type(const int column) const noexcept
Returns the type of the specified column.
Definition: Statement.h:215
sqlite3_stmt * handle() const noexcept
Returns pointer to the underlying "sqlite3_stmt" object.
Definition: Statement.cpp:32
Helps when iterating over rows in a "SELECT" statement.
Definition: Statement.h:592
row(sqlite3_stmt *const statement) noexcept
Constructs a row object from a sqlite3_stmt.
Definition: Statement.h:313
int execute() const
Executes a prepared statement and will return the number of changes to the database.
Definition: Statement.cpp:57
bindtype
Used to specify the way to bind a value to a statement.
Definition: SQLiteEnums.h:23
datatype
Every value in SQLite has one of the following fundamental datatypes.
Definition: SQLiteEnums.h:13
value get_value(const std::string &name) const
Returns the specified column value as a value object.
Definition: Statement.h:185
int column_count() const noexcept
Returns the number of columns in the result set returned by the prepared statement.
Definition: Statement.h:234
void reset() const
Resets a prepared statement object back to its initial state.
Definition: Statement.h:535
statement(const dbconnection &connection, const std::string &text, Values &&...values)
Creates, prepares, and binds values into an SQL statement.
Definition: Statement.h:364
int get_bytes(const std::string &name) const noexcept
Returns the size in bytes of the column value.
Definition: Statement.h:205
void bind_all(Values &&...values) const
Binds values to parameters in an SQL prepared statement.
Definition: Statement.h:511
const std::string get_string(const std::string &name) const noexcept
Returns the specified column value as a string.
Definition: Statement.h:146
value operator[](int column) const
Access specified element of a row.
Definition: Statement.h:328
Represents a single SQL statement that has been compiled into binary form and is ready to be evaluate...
Definition: Statement.h:350
const blob get_blob(const std::string &name) const noexcept
Returns the specified column value as a Blob object.
Definition: Statement.h:126
Represents a returned row when stepping through a "SELECT" statement.
Definition: Statement.h:307
datatype get_type(const std::string &name) const noexcept
Returns the type of the specified column.
Definition: Statement.h:224
void clear_bindings(Values &&...values) const
Resets all SQL parameters to NULL.
Definition: Statement.h:520
row_iterator() noexcept=default
Default constructor.
double get_double(const std::string &name) const noexcept
Returns the specified column value as a double.
Definition: Statement.h:106
row_iterator end(const statement &statement) noexcept
Returns an iterator to the end.
Definition: Statement.cpp:11
row_iterator begin(const statement &statement) noexcept
Returns an iterator to the first row of a statement.
Definition: Statement.cpp:6
int64_t get_int64(const std::string &name) const noexcept
Returns the specified column value as a 64-bit integer.
Definition: Statement.h:68
int get_bytes(const int column) const noexcept
Returns the size in bytes of the column value.
Definition: Statement.h:196
value operator[](const std::string &name) const
Access specified element of a row.
Definition: Statement.h:337
sqlite3_stmt * handle() const noexcept
Returns pointer to the underlying "sqlite3_stmt" object.
Definition: Statement.h:319
int get_int(const std::string &name) const noexcept
Returns the specified column value as an integer.
Definition: Statement.h:49
double get_double(const int column) const noexcept
Returns the specified column value as a double.
Definition: Statement.h:97
int64_t get_int64(const int column) const noexcept
Returns the specified column value as a 64-bit integer.
Definition: Statement.h:59
statement() noexcept
Default constructor.
Definition: Statement.cpp:20
const std::string get_string(const int column) const noexcept
Returns the specified column value as a string.
Definition: Statement.h:136
Class that represents a connection to a database.
Definition: DBConnection.h:24
row_iterator & operator++() noexcept
Increment iterator to the next row object of the statement.
Definition: Statement.cpp:139
int get_int(const int column) const noexcept
Returns the specified column value as an integer.
Definition: Statement.h:40
A "Binary Large OBject".
Definition: Blob.h:20
void prepare(dbconnection const &connection, const std::string &text, Values &&...values)
Turn an SQL query into byte code.
Definition: Statement.h:408