sqlite.hpp
Go to the documentation of this file.
1 
23 #pragma once
24 #include <sqlite3.h>
25 #include <cstring>
26 #include <cstdint>
27 #include <string>
28 #include <vector>
29 #include <stdexcept>
30 
31 #if __cplusplus > 201402L
32  #define CPP_SQLITE_NODISCARD [[nodiscard]]
33 #else
34  #define CPP_SQLITE_NODISCARD
35 #endif
36 
37 #if defined(CPP_SQLITE_NOTHROW)
38  #define CPP_SQLITE_THROW(...) return false
39 #else
40  #define CPP_SQLITE_THROW(...) throw sqlite::Error(__VA_ARGS__)
41 #endif
42 
43 namespace sqlite
44 {
45  class Error : public std::runtime_error
46  {
47  public:
48  explicit Error(const char* message, int errorCode = SQLITE_ERROR)
49  : std::runtime_error(message), m_errorCode(errorCode)
50  {
51 
52  }
53 
54  explicit Error(const std::string& message, int errorCode = SQLITE_ERROR)
55  : std::runtime_error(message), m_errorCode(errorCode)
56  {
57 
58  }
59 
61  int GetCode() const
62  {
63  return m_errorCode;
64  }
65 
66  private:
68  };
69 
70  namespace Priv
71  {
72  inline bool CheckError(sqlite3* db, int code)
73  {
74  if(code != SQLITE_OK && code != SQLITE_DONE)
75  {
76  const int extendedCode = sqlite3_extended_errcode(db);
77  std::string errstr = sqlite3_errstr(extendedCode);
78  std::string errmsg = sqlite3_errmsg(db);
79 
80  CPP_SQLITE_THROW(errstr + ": " + errmsg, extendedCode);
81  }
82 
83  return true;
84  }
85 
86  inline bool CheckError(int code)
87  {
88  if(code != SQLITE_OK && code != SQLITE_DONE)
89  {
90  std::string errstr = std::string("SQL error: ") + sqlite3_errstr(code);
91  CPP_SQLITE_THROW(errstr, code);
92  }
93 
94  return true;
95  }
96  }
97 
98  class Connection
99  {
100  public:
101  Connection() : m_connection(nullptr) {}
102 
103  explicit Connection(const std::string& filename)
104  {
105  this->Open(filename);
106  }
107 
108  Connection(const Connection&) = delete;
109 
110  Connection(Connection&& other) noexcept
111  {
112  this->m_connection = other.m_connection;
113  other.m_connection = nullptr;
114  }
115 
116  virtual ~Connection() noexcept
117  {
118  try
119  {
120  this->Close();
121  }
122  catch(...)
123  {
124 
125  }
126  }
127 
128  Connection& operator=(const Connection&) = delete;
129 
130  Connection& operator=(Connection&& other) noexcept
131  {
132  if(&other != this)
133  {
134  this->m_connection = other.m_connection;
135  other.m_connection = nullptr;
136  }
137 
138  return *this;
139  }
140 
141  bool Open(const std::string& filename)
142  {
143  return sqlite::Priv::CheckError(sqlite3_open(filename.data(), &m_connection));
144  }
145 
146  bool Close()
147  {
148  const auto result = Priv::CheckError(sqlite3_close(m_connection));
149  m_connection = nullptr;
150 
151  return result;
152  }
153 
155  int GetExtendedResult() const
156  {
157  return sqlite3_extended_errcode(m_connection);
158  }
159 
161  sqlite3* GetPtr()
162  {
163  return m_connection;
164  }
165 
166  private:
167  sqlite3* m_connection = nullptr;
168  };
169 
170  class Blob
171  {
172  public:
173  Blob(const void* data, int32_t bytes)
174  {
175  m_data.resize(bytes);
176  std::memcpy(&m_data.at(0), data, bytes);
177  }
178 
179  explicit Blob(std::vector<unsigned char> data)
180  : m_data(std::move(data))
181  {
182 
183  }
184 
186  uint32_t GetSize() const
187  {
188  return m_data.size();
189  }
190 
192  unsigned char* GetData()
193  {
194  return m_data.data();
195  }
196 
198  const unsigned char* GetData() const
199  {
200  return m_data.data();
201  }
202 
203  private:
204  std::vector<unsigned char> m_data;
205  };
206 
208  class NOBlob
209  {
210  public:
211  NOBlob(const void* ptr, uint32_t bytes)
212  : m_ptr(ptr), m_bytes(bytes)
213  {
214 
215  }
216 
218  uint32_t GetSize() const
219  {
220  return m_bytes;
221  }
222 
223  const void* GetData()
224  {
225  return m_ptr;
226  }
227 
229  const void* GetData() const
230  {
231  return m_ptr;
232  }
233 
234  private:
235  const void* m_ptr;
236  uint32_t m_bytes;
237  };
238 
239  namespace Priv
240  {
241  inline void Append(sqlite3_stmt* statement, int index, const int32_t& data)
242  {
243  sqlite::Priv::CheckError(sqlite3_bind_int(statement, index, data));
244  }
245 
246  inline void Append(sqlite3_stmt* statement, int index, const int64_t& data)
247  {
248  sqlite::Priv::CheckError(sqlite3_bind_int64(statement, index, data));
249  }
250 
251  inline void Append(sqlite3_stmt* statement, int index, const float& data)
252  {
253  sqlite::Priv::CheckError(sqlite3_bind_double(statement, index, static_cast<double>(data)));
254  }
255 
256  inline void Append(sqlite3_stmt* statement, int index, const double& data)
257  {
258  sqlite::Priv::CheckError(sqlite3_bind_double(statement, index, data));
259  }
260 
261  inline void Append(sqlite3_stmt* statement, int index, const std::string& data)
262  {
263  sqlite::Priv::CheckError(sqlite3_bind_text(statement, index, data.data(), static_cast<int>(data.size()), nullptr));
264  }
265 
266  inline void Append(sqlite3_stmt* statement, int index, const char* data)
267  {
268  sqlite::Priv::CheckError(sqlite3_bind_text(statement, index, data, static_cast<int>(std::strlen(data)), nullptr));
269  }
270 
271  inline void Append(sqlite3_stmt* statement, int index, const sqlite::Blob& blob)
272  {
273  sqlite::Priv::CheckError(sqlite3_bind_blob(statement, index, blob.GetData(), static_cast<int>(blob.GetSize()), nullptr));
274  }
275 
276  inline void Append(sqlite3_stmt* statement, int index, const sqlite::NOBlob& blob)
277  {
278  sqlite::Priv::CheckError(sqlite3_bind_blob(statement, index, blob.GetData(), static_cast<int>(blob.GetSize()), nullptr));
279  }
280 
281  template<typename Arg>
282  inline void AppendToQuery(sqlite3_stmt* statement, int index, const Arg& arg)
283  {
284  sqlite::Priv::Append(statement, index, arg);
285  }
286 
287  template<typename First, typename ... Args>
288  inline void AppendToQuery(sqlite3_stmt* statement, int index, const First& first, const Args&... args)
289  {
290  sqlite::Priv::Append(statement, index, first);
291  sqlite::Priv::AppendToQuery(statement, ++index, args...);
292  }
293 
294  struct Statement
295  {
296  Statement() : handle(nullptr) {}
297 
298  Statement(sqlite::Connection& connection, const std::string& command)
299  {
300  auto* db = connection.GetPtr();
301 
302  const int code = sqlite3_prepare_v2(
303  db,
304  command.data(),
305  static_cast<int>(command.size()),
306  &handle,
307  nullptr);
308 
309  Priv::CheckError(db, code);
310  }
311 
312  Statement(Statement&& other) noexcept
313  {
314  std::swap(handle, other.handle);
315  }
316 
318  {
319  sqlite::Priv::CheckError(sqlite3_finalize(handle));
320  }
321 
322  Statement& operator=(Statement&& other) noexcept
323  {
324  handle = other.handle;
325  other.handle = nullptr;
326 
327  return *this;
328  }
329 
331  bool Advance() const
332  {
333  const int code = sqlite3_step(handle);
334 
335  if(code == SQLITE_ROW)
336  {
337  return true;
338  }
339 
341  Reset();
342 
343  return false;
344  }
345 
346  bool Reset() const
347  {
348  return sqlite::Priv::CheckError(sqlite3_reset(handle));
349  }
350 
352  int ColumnCount() const
353  {
354  Reset();
355 
356  if(!Advance())
357  {
358  return 0;
359  }
360 
361  const int count = sqlite3_column_count(handle);
362  Reset();
363 
364  return count;
365  }
366 
368  std::string GetColumnName(int columnIndex) const
369  {
370  Reset();
371 
372  if(!Advance())
373  {
374 #ifndef CPP_SQLITE_NOTHROW
375  throw sqlite::Error("SQL error: invalid column index");
376 #endif
377  }
378 
379  std::string name = sqlite3_column_name(handle, columnIndex);
380 
381  if(name.empty())
382  {
383 #ifndef CPP_SQLITE_NOTHROW
384  throw sqlite::Error("SQL error: failed to get column name at index " + std::to_string(columnIndex));
385 #endif
386  }
387 
388  Reset();
389 
390  return name;
391  }
392 
393  template<typename T>
395  T Get(int) const
396  {
397  static_assert(sizeof(T) == -1, "SQL error: invalid column data type");
398  }
399 
400  sqlite3_stmt* handle = nullptr;
401  };
402 
403  template<>
404  inline float Statement::Get(int col) const
405  {
406  return static_cast<float>(sqlite3_column_double(handle, col));
407  }
408 
409  template<>
410  inline double Statement::Get(int col) const
411  {
412  return sqlite3_column_double(handle, col);
413  }
414 
415  template<>
416  inline int32_t Statement::Get(int col) const
417  {
418  return sqlite3_column_int(handle, col);
419  }
420 
421  template<>
422  inline int64_t Statement::Get(int col) const
423  {
424  return sqlite3_column_int64(handle, col);
425  }
426 
427  template<>
428  inline std::string Statement::Get(int col) const
429  {
430  const unsigned char* bytes = sqlite3_column_text(handle, col);
431  const int size = sqlite3_column_bytes(handle, col);
432 
433  if(size == 0)
434  {
435  return "";
436  }
437 
438  return {reinterpret_cast<const char*>(bytes), static_cast<std::string::size_type>(size)};
439  }
440 
441  template<>
442  inline sqlite::Blob Statement::Get(int col) const
443  {
444  const void* bytes = sqlite3_column_blob(handle, col);
445  const int size = sqlite3_column_bytes(handle, col);
446 
447  return {bytes, size};
448  }
449  }
450 
451  class Type
452  {
453  private:
454  Type(const sqlite::Priv::Statement& statement, int col)
455  : m_statement(statement), m_columnIndex(col)
456  {
457 
458  }
459  public:
460  template<typename T>
461  operator T() const
462  {
463  return m_statement.Get<T>(m_columnIndex);
464  }
465 
466  friend class Result;
467 
468  private:
470  const int m_columnIndex;
471  };
472 
473  class Result
474  {
475  explicit Result(sqlite::Priv::Statement&& statement)
476  : m_statement(std::move(statement))
477  {
478 
479  }
480 
481  public:
482  Result() = default;
483 
484  Result(Result&& other) noexcept
485  {
486  m_statement = std::move(other.m_statement);
487  }
488 
489  Result& operator=(Result&& other) noexcept
490  {
491  m_statement = std::move(other.m_statement);
492 
493  return *this;
494  }
495 
497  bool HasData() const
498  {
499  return ColumnCount() > 0;
500  }
501 
503  int ColumnCount() const
504  {
505  return m_statement.ColumnCount();
506  }
507 
508  bool Reset() const
509  {
510  return m_statement.Reset();
511  }
512 
514  bool Next() const
515  {
516  return m_statement.Advance();
517  }
518 
520  Type Get(int columnIndex) const
521  {
522  return {m_statement, columnIndex};
523  }
524 
526  std::string GetColumnName(int columnIndex) const
527  {
528  return m_statement.GetColumnName(columnIndex);
529  }
530 
531  friend void Statement(sqlite::Connection&, const std::string&);
532 
533  template<typename First, typename ... Args>
534  friend Result Query(sqlite::Connection& connection, const std::string& command, const First& first, const Args... args);
535  friend Result Query(sqlite::Connection& connection, const std::string& command);
536 
537  private:
539  };
540 
541  template<typename First, typename ... Args>
542  inline void Statement(sqlite::Connection& connection, const std::string& command, const First& first, const Args... args)
543  {
544  sqlite::Priv::Statement statement(connection, command);
545  sqlite::Priv::AppendToQuery<First, Args...>(statement.handle, 1, first, args...);
546 
547  (void)statement.Advance();
548  }
549 
550  inline void Statement(sqlite::Connection& connection, const std::string& command)
551  {
552  sqlite::Priv::Statement statement(connection, command);
553 
554  (void)statement.Advance();
555  }
556 
557  template<typename First, typename ... Args>
559  inline Result Query(sqlite::Connection& connection, const std::string& command, const First& first, const Args... args)
560  {
561  sqlite::Priv::Statement statement(connection, command);
562  sqlite::Priv::AppendToQuery<First, Args...>(statement.handle, 1, first, args...);
563 
564  return Result(std::move(statement));
565  }
566 
568  inline Result Query(sqlite::Connection& connection, const std::string& command)
569  {
570  sqlite::Priv::Statement statement(connection, command);
571 
572  return Result(std::move(statement));
573  }
574 
576  {
577  sqlite3_backup* backup = sqlite3_backup_init(to.GetPtr(), "main", from.GetPtr(), "main");
578 
579  if(!backup)
580  {
581  CPP_SQLITE_THROW("SQL error: failed to initialize backup");
582  }
583 
584  if(!Priv::CheckError(sqlite3_backup_step(backup, -1)))
585  {
586  return false;
587  }
588 
589  if(!Priv::CheckError(sqlite3_backup_finish(backup)))
590  {
591  return false;
592  }
593 
594  return true;
595  }
596 
597  inline bool Backup(sqlite::Connection& from, const std::string& filename)
598  {
599  sqlite::Connection to(filename);
600 
601  return sqlite::Backup(from, to);
602  }
603 }
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
sqlite::Connection::~Connection
virtual ~Connection() noexcept
Definition: sqlite.hpp:116
sqlite::Priv::Append
void Append(sqlite3_stmt *statement, int index, const int32_t &data)
Definition: sqlite.hpp:241
sqlite::Priv::Statement::operator=
Statement & operator=(Statement &&other) noexcept
Definition: sqlite.hpp:322
sqlite::NOBlob
Definition: sqlite.hpp:208
lexyd::bytes
constexpr auto bytes
Matches N arbitrary bytes.
Definition: byte.hpp:55
sqlite::Connection::m_connection
sqlite3 * m_connection
Definition: sqlite.hpp:167
sqlite::Priv::Statement::Reset
bool Reset() const
Definition: sqlite.hpp:346
sqlite::Priv::Statement::ColumnCount
CPP_SQLITE_NODISCARD int ColumnCount() const
Definition: sqlite.hpp:352
sqlite::Priv::Statement::~Statement
~Statement()
Definition: sqlite.hpp:317
CPP_SQLITE_NODISCARD
#define CPP_SQLITE_NODISCARD
Definition: sqlite.hpp:34
command
ROSLIB_DECL std::string command(const std::string &cmd)
sqlite::Blob::GetData
const CPP_SQLITE_NODISCARD unsigned char * GetData() const
Definition: sqlite.hpp:198
sqlite::Connection::Connection
Connection()
Definition: sqlite.hpp:101
sqlite::NOBlob::GetData
const CPP_SQLITE_NODISCARD void * GetData() const
Definition: sqlite.hpp:229
sqlite::Result::Next
CPP_SQLITE_NODISCARD bool Next() const
Definition: sqlite.hpp:514
sqlite::Type::Type
Type(const sqlite::Priv::Statement &statement, int col)
Definition: sqlite.hpp:454
sqlite::Priv::Statement
Definition: sqlite.hpp:294
sqlite::Result::HasData
CPP_SQLITE_NODISCARD bool HasData() const
Definition: sqlite.hpp:497
sqlite::Error::GetCode
CPP_SQLITE_NODISCARD int GetCode() const
Definition: sqlite.hpp:61
sqlite::Connection::Connection
Connection(Connection &&other) noexcept
Definition: sqlite.hpp:110
sqlite::Priv::Statement::Statement
Statement()
Definition: sqlite.hpp:296
sqlite::Blob::GetSize
CPP_SQLITE_NODISCARD uint32_t GetSize() const
Definition: sqlite.hpp:186
sqlite::NOBlob::GetData
const void * GetData()
Definition: sqlite.hpp:223
detail::void
j template void())
Definition: json.hpp:4893
sqlite::NOBlob::m_bytes
uint32_t m_bytes
Definition: sqlite.hpp:236
sqlite::Priv::CheckError
bool CheckError(sqlite3 *db, int code)
Definition: sqlite.hpp:72
sqlite::Blob::GetData
CPP_SQLITE_NODISCARD unsigned char * GetData()
Definition: sqlite.hpp:192
sqlite::Result::GetColumnName
CPP_SQLITE_NODISCARD std::string GetColumnName(int columnIndex) const
Definition: sqlite.hpp:526
sqlite::Result::Result
Result(Result &&other) noexcept
Definition: sqlite.hpp:484
sqlite::Result::operator=
Result & operator=(Result &&other) noexcept
Definition: sqlite.hpp:489
sqlite::Statement
void Statement(sqlite::Connection &connection, const std::string &command, const First &first, const Args... args)
Definition: sqlite.hpp:542
sqlite::Blob::Blob
Blob(std::vector< unsigned char > data)
Definition: sqlite.hpp:179
lexy::count
constexpr auto count
Sink that counts all arguments.
Definition: fold.hpp:88
sqlite::Result::m_statement
sqlite::Priv::Statement m_statement
Definition: sqlite.hpp:538
sqlite::Connection::operator=
Connection & operator=(Connection &&other) noexcept
Definition: sqlite.hpp:130
sqlite::Error::m_errorCode
int m_errorCode
Definition: sqlite.hpp:67
sqlite::Result
Definition: sqlite.hpp:473
sqlite::Blob
Definition: sqlite.hpp:170
sqlite::Connection::GetPtr
CPP_SQLITE_NODISCARD sqlite3 * GetPtr()
Definition: sqlite.hpp:161
sqlite::Result::ColumnCount
CPP_SQLITE_NODISCARD int ColumnCount() const
Definition: sqlite.hpp:503
sqlite::Error::Error
Error(const std::string &message, int errorCode=SQLITE_ERROR)
Definition: sqlite.hpp:54
sqlite::NOBlob::NOBlob
NOBlob(const void *ptr, uint32_t bytes)
Definition: sqlite.hpp:211
sqlite::Priv::Statement::GetColumnName
CPP_SQLITE_NODISCARD std::string GetColumnName(int columnIndex) const
Definition: sqlite.hpp:368
sqlite::Result::Reset
bool Reset() const
Definition: sqlite.hpp:508
to_string
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.hpp:24456
sqlite::Connection::operator=
Connection & operator=(const Connection &)=delete
sqlite::Blob::Blob
Blob(const void *data, int32_t bytes)
Definition: sqlite.hpp:173
sqlite::Priv::Statement::Statement
Statement(sqlite::Connection &connection, const std::string &command)
Definition: sqlite.hpp:298
sqlite::Result::Result
Result(sqlite::Priv::Statement &&statement)
Definition: sqlite.hpp:475
sqlite::Priv::Statement::Statement
Statement(Statement &&other) noexcept
Definition: sqlite.hpp:312
sqlite::Connection::Close
bool Close()
Definition: sqlite.hpp:146
sqlite::Result::Query
friend Result Query(sqlite::Connection &connection, const std::string &command, const First &first, const Args... args)
Definition: sqlite.hpp:559
sqlite::Connection::Open
bool Open(const std::string &filename)
Definition: sqlite.hpp:141
sqlite::Priv::Statement::Get
CPP_SQLITE_NODISCARD T Get(int) const
Definition: sqlite.hpp:395
sqlite::Result::Result
Result()=default
std
Definition: std.hpp:30
sqlite::Blob::m_data
std::vector< unsigned char > m_data
Definition: sqlite.hpp:204
sqlite::Connection::GetExtendedResult
CPP_SQLITE_NODISCARD int GetExtendedResult() const
Definition: sqlite.hpp:155
sqlite::Priv::AppendToQuery
void AppendToQuery(sqlite3_stmt *statement, int index, const Arg &arg)
Definition: sqlite.hpp:282
sqlite::Type::m_statement
const sqlite::Priv::Statement & m_statement
Definition: sqlite.hpp:469
sqlite::Error::Error
Error(const char *message, int errorCode=SQLITE_ERROR)
Definition: sqlite.hpp:48
sqlite
Definition: sqlite.hpp:43
sqlite::Result::Get
CPP_SQLITE_NODISCARD Type Get(int columnIndex) const
Definition: sqlite.hpp:520
BT::Result
Expected< std::monostate > Result
Definition: basic_types.h:333
sqlite::Backup
bool Backup(sqlite::Connection &from, sqlite::Connection &to)
Definition: sqlite.hpp:575
sqlite::Query
CPP_SQLITE_NODISCARD Result Query(sqlite::Connection &connection, const std::string &command, const First &first, const Args... args)
Definition: sqlite.hpp:559
std::swap
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:24537
sqlite::Error
Definition: sqlite.hpp:45
sqlite::Priv::Statement::Advance
CPP_SQLITE_NODISCARD bool Advance() const
Definition: sqlite.hpp:331
sqlite::Type::m_columnIndex
const int m_columnIndex
Definition: sqlite.hpp:470
sqlite::Priv::Statement::handle
sqlite3_stmt * handle
Definition: sqlite.hpp:400
sqlite::NOBlob::GetSize
CPP_SQLITE_NODISCARD uint32_t GetSize() const
Definition: sqlite.hpp:218
sqlite::Type
Definition: sqlite.hpp:451
sqlite::Connection
Definition: sqlite.hpp:98
sqlite::Connection::Connection
Connection(const std::string &filename)
Definition: sqlite.hpp:103
sqlite::Result::Statement
friend void Statement(sqlite::Connection &, const std::string &)
Definition: sqlite.hpp:550
sqlite::NOBlob::m_ptr
const void * m_ptr
Definition: sqlite.hpp:235
CPP_SQLITE_THROW
#define CPP_SQLITE_THROW(...)
Definition: sqlite.hpp:40


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:08