SQLite for C++
sqlite_cpp.h
Go to the documentation of this file.
1 
3 #include "sqlite3.h"
4 #include <map>
5 #include <queue>
6 #include <vector>
7 #include <string>
8 #include <memory>
9 
12 namespace SQLite {
14  struct conn_base {
15  public:
16  sqlite3* db = nullptr;
17 
19  sqlite3** get_ref() {
20  return &(this->db);
21  }
22 
23  void close() {
24  if (db) {
25  sqlite3_close(db);
26  db = nullptr;
27  }
28  };
29  conn_base() {};
30  ~conn_base() {
31  this->close();
32  }
33  };
34 
36  struct stmt_base {
37  public:
38  stmt_base() {};
39  ~stmt_base() {
40  // Note: Calling sqlite3_finalize on a nullptr is harmless
41  sqlite3_finalize(this->stmt);
42  }
43 
44  void close() {
45  if (stmt) {
46  sqlite3_finalize(stmt);
47  stmt = nullptr;
48  }
49  }
50 
51  sqlite3_stmt* stmt = nullptr;
52  };
53 
55  class Conn {
56 
59  public:
60  PreparedStatement(Conn& conn, const std::string& stmt);
61  template<typename... Args>
62 
64  void bind(Args... args) {
73  if (sizeof...(Args) > this->params) {
74  throw ValueError("Too many arguments to bind() " +
75  std::to_string(this->params) + " expected " + std::to_string(sizeof...(Args)) + " specified");
76  }
77 
78  size_t i = 0;
79  _bind_many(i, args...); // Recurse through templates
80  this->next();
81  }
82 
83  template<typename T>
84  void bind(const size_t i, const T value) {
85  static_assert(false, "Cannot call bind() on values of this type. Supported types are:"
86  " char *, string, int, long int, and double.");
87  }
88 
89  template<>
90  inline void bind(const size_t i, const char* value) {
91  sqlite3_bind_text(
92  this->get_ptr(), // Pointer to prepared statement
93  i + 1, // Index of parameter to set
94  value, // Value to bind
95  strlen(value), // Size of string in bytes
96  SQLITE_TRANSIENT); // String destructor
97  }
98 
99  template<>
100  inline void bind(const size_t i, const std::string value) {
106  sqlite3_bind_text(
107  this->get_ptr(), // Pointer to prepared statement
108  i + 1, // Index of parameter to set
109  value.c_str(), // Value to bind
110  value.size(), // Size of string in bytes
111  SQLITE_TRANSIENT); // String destructor
112  }
113 
114  template<>
115  inline void bind(const size_t i, const int value) {
117  sqlite3_bind_int(this->get_ptr(), i + 1, value);
118  }
119 
120  template<>
121  inline void bind(const size_t i, const long int value) {
123  sqlite3_bind_int64(this->get_ptr(), i + 1, value);
124  }
125 
126  template<>
127  void bind(const size_t i, double value) {
129  sqlite3_bind_double(this->get_ptr(), i + 1, value);
130  }
132 
133  sqlite3_stmt* get_ptr();
134  void commit();
135  void next();
136  void close() noexcept;
137 
138  protected:
139  int params;
140  Conn* conn;
141  std::shared_ptr<stmt_base> base = std::make_shared<stmt_base>();
142  const char * unused;
143 
144  private:
146  template<typename T>
148  void _bind_many(size_t i, T value) {
149  bind<T>(i, value);
150  i++;
151  }
152 
153  template<typename T, typename... Args>
154  void _bind_many(size_t i, T value, Args... args) {
155  bind<T>(i, value);
156  i++;
157  _bind_many(i, args...); // Recurse through templates
158  }
160  };
161 
164  public:
165  std::vector<std::string> get_col_names();
166  std::vector<std::string> get_row();
167  int num_cols();
168  bool next();
169  using PreparedStatement::close;
170  using PreparedStatement::PreparedStatement;
171  };
172 
173  public:
174  Conn(const char * db_name);
175  Conn(const std::string db_name);
176  void exec(const std::string query);
177  Conn::PreparedStatement prepare(const std::string& stmt);
178  Conn::ResultSet query(const std::string& stmt);
179  void close() noexcept;
180 
181  sqlite3* get_ptr();
182  std::shared_ptr<conn_base> base =
183  std::make_shared<conn_base>();
184  char * error_message;
185  private:
186  std::queue<PreparedStatement*> stmts;
188  };
189 
193 
195  class DatabaseClosed : public std::runtime_error {
196  public:
197  DatabaseClosed() :runtime_error("Attempted operation on a closed database.") {};
198  };
199 
201  class StatementClosed : public std::runtime_error {
202  public:
203  StatementClosed() :runtime_error("Attempted operation on a closed statement.") {};
204  };
205 
207  class ValueError : public std::runtime_error {
208  public:
209  ValueError() :runtime_error("[Value Error] Invalid value or value(s).") {};
210  ValueError(const std::string& msg) :runtime_error("[Value Error] " + msg) {};
211  };
212 
214  class SQLiteError : public std::runtime_error {
215  public:
216  SQLiteError(const std::string& msg) :runtime_error("[SQLite Error] " + msg) {};
217  };
218 
220  const std::map<int, std::string> SQLITE_ERROR_MSG = {
221  { 1, "SQLITE_ERROR: Generic SQLite Error" },
222  { 19, "SQLITE_CONSTRAINT: SQL constrainted violated" }
223  };
224 
225  const std::map<int, std::string> SQLITE_EXT_ERROR_MSG = {
226  { 787, "SQLITE_CONSTRAINT_FOREIGNKEY: Foreign key constraint failed" },
227  { 1555, "SQLITE_CONSTRAINT_PRIMARYKEY: Primary key constraint failed" }
228  };
229 
230  void throw_sqlite_error(const int& error_code,
231  const int& ext_error_code=-1);
233 }
Definition: sqlite_cpp.h:163
void bind(const size_t i, const long int value)
Definition: sqlite_cpp.h:121
const std::map< int, std::string > SQLITE_ERROR_MSG
Definition: sqlite_cpp.h:220
Definition: sqlite_cpp.h:214
Definition: sqlite_cpp.h:36
Definition: sqlite_cpp.h:55
Definition: sqlite_cpp.h:58
void bind(const size_t i, double value)
Definition: sqlite_cpp.h:127
Definition: sqlite_cpp.h:207
void bind(const size_t i, const int value)
Definition: sqlite_cpp.h:115
Definition: sqlite_cpp.h:201
Definition: sqlite_cpp.h:14
sqlite3 ** get_ref()
Definition: sqlite_cpp.h:19
char * error_message
Definition: sqlite_cpp.h:184
Definition: sqlite_cpp.cpp:3
std::queue< PreparedStatement * > stmts
Definition: sqlite_cpp.h:186
Definition: sqlite_cpp.h:195
void bind(const size_t i, const std::string value)
Definition: sqlite_cpp.h:100