Synchronize notmuch mail across machines
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sqlstmt.h 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // -*- C++ -*-
  2. #ifndef _SQLSTMT_H_
  3. #define _SQLSTMT_H_ 1
  4. #include <cassert>
  5. #include <string>
  6. #include <tuple>
  7. #include <stdexcept>
  8. #include <sqlite3.h>
  9. using i64 = sqlite3_int64;
  10. struct sqlerr_t : public std::runtime_error {
  11. sqlerr_t (const std::string &msg) : std::runtime_error (msg) {}
  12. };
  13. /* A sqldone_t is thrown if you ask for data when no rows are left */
  14. struct sqldone_t : public std::runtime_error {
  15. sqldone_t (const std::string &msg) : std::runtime_error (msg) {}
  16. };
  17. class sqlstmt_t {
  18. sqlite3_stmt *stmt_;
  19. int status_ = SQLITE_OK;
  20. sqlstmt_t &set_status (int status);
  21. void fail ();
  22. void ensure_row () { if (status_ != SQLITE_ROW) fail(); }
  23. public:
  24. explicit sqlstmt_t(sqlite3_stmt *stmt) : stmt_(stmt) {}
  25. explicit sqlstmt_t(sqlite3 *db, const char *fmt, ...);
  26. sqlstmt_t(const sqlstmt_t &r);
  27. sqlstmt_t(sqlstmt_t &&r) : stmt_ (r.stmt_) { r.stmt_ = nullptr; }
  28. ~sqlstmt_t() { sqlite3_finalize (stmt_); }
  29. sqlite3_stmt *get() { return stmt_; }
  30. sqlite3 *getdb() { return sqlite3_db_handle(stmt_); }
  31. int status() const { return status_; }
  32. bool row() {
  33. if (status_ == SQLITE_ROW)
  34. return true;
  35. // Something like SQLITE_OK indicates row() not used after step()
  36. assert (status_ == SQLITE_DONE);
  37. return false;
  38. }
  39. bool done() { return !row(); }
  40. sqlstmt_t &step() { return set_status(sqlite3_step (stmt_)); }
  41. sqlstmt_t &reset() { return set_status(sqlite3_reset (stmt_)); }
  42. /* Access columns */
  43. template<typename T> T column(int);
  44. bool null(int i) {
  45. ensure_row();
  46. return sqlite3_column_type (stmt_, i) == SQLITE_NULL;
  47. }
  48. sqlite3_int64 integer(int i) {
  49. ensure_row();
  50. return sqlite3_column_int64 (stmt_, i);
  51. }
  52. double real(int i) {
  53. ensure_row();
  54. return sqlite3_column_double (stmt_, i);
  55. }
  56. std::string str(int i) {
  57. ensure_row();
  58. return { static_cast<const char *> (sqlite3_column_blob (stmt_, i)),
  59. size_t (sqlite3_column_bytes (stmt_, i)) };
  60. }
  61. const char *c_str(int i) {
  62. ensure_row();
  63. return reinterpret_cast<const char *> (sqlite3_column_text (stmt_, i));
  64. }
  65. sqlite3_value *value(int i) {
  66. ensure_row();
  67. return sqlite3_column_value(stmt_, i);
  68. }
  69. /* Bind parameters */
  70. sqlstmt_t &bind_null(int i) {
  71. return set_status (sqlite3_bind_null(stmt_, i));
  72. }
  73. sqlstmt_t &bind_int(int i, sqlite3_int64 v) {
  74. return set_status (sqlite3_bind_int64(stmt_, i, v));
  75. }
  76. sqlstmt_t &bind_real(int i, double v) {
  77. return set_status (sqlite3_bind_double(stmt_, i, v));
  78. }
  79. sqlstmt_t &bind_text(int i, const std::string &v) {
  80. return set_status (sqlite3_bind_text(stmt_, i, v.data(), v.size(),
  81. SQLITE_STATIC));
  82. }
  83. sqlstmt_t &bind_text(int i, std::string &&v) {
  84. return set_status (sqlite3_bind_text(stmt_, i, v.data(), v.size(),
  85. SQLITE_TRANSIENT));
  86. }
  87. sqlstmt_t &bind_text(int i, const char *p, int len = -1) {
  88. return set_status (sqlite3_bind_text(stmt_, i, p, len, SQLITE_STATIC));
  89. }
  90. sqlstmt_t &bind_blob(int i, const void *p, int len) {
  91. return set_status (sqlite3_bind_blob(stmt_, i, p, len, SQLITE_STATIC));
  92. }
  93. sqlstmt_t &bind_value(int i, const sqlite3_value *v) {
  94. return set_status (sqlite3_bind_value (stmt_, i, v));
  95. }
  96. /* Overloaded bind */
  97. sqlstmt_t &bind(int i, std::nullptr_t) { return bind_null(i); }
  98. sqlstmt_t &bind(int i, sqlite3_int64 v) { return bind_int(i, v); }
  99. sqlstmt_t &bind(int i, int v) { return bind_int(i, v); }
  100. sqlstmt_t &bind(int i, unsigned v) { return bind_int(i, v); }
  101. sqlstmt_t &bind(int i, const double &v) { return bind_real(i, v); }
  102. sqlstmt_t &bind(int i, const std::string &v) { return bind_text(i, v); }
  103. sqlstmt_t &bind(int i, std::string &&v) { return bind_text(i, std::move(v)); }
  104. sqlstmt_t &bind(int i, const char *v) { return bind_text(i, v); }
  105. sqlstmt_t &bind(int i, const sqlite3_value *v) { return bind_value(i, v); }
  106. /* Bind multiple parameters at once */
  107. sqlstmt_t &_param(int) { return *this; }
  108. template<typename H, typename... T>
  109. sqlstmt_t &_param(int i, H&& h, T&&... t) {
  110. return this->bind(i, std::forward<H>(h))._param(i+1, std::forward<T>(t)...);
  111. }
  112. template<typename... Args> sqlstmt_t &param(Args&&... args) {
  113. return _param (1, std::forward<Args> (args)...);
  114. }
  115. /* Bind tuple */
  116. template<size_t N> struct _tparm_helper {
  117. template<typename... Args>
  118. static sqlstmt_t &go(sqlstmt_t &s, const std::tuple<Args...> &t) {
  119. return _tparm_helper<N-1>::go(s.bind(N, std::get<N-1>(t)), t);
  120. }
  121. };
  122. template<typename... Args>
  123. sqlstmt_t &tparam(const std::tuple<Args...> &t) {
  124. return _tparm_helper<sizeof...(Args)>::go(*this, t);
  125. }
  126. };
  127. template<> struct sqlstmt_t::_tparm_helper<0> {
  128. template<typename... Args>
  129. static sqlstmt_t &go(sqlstmt_t &s, const std::tuple<Args...> &t) { return s; }
  130. };
  131. template<> inline bool
  132. sqlstmt_t::column(int i)
  133. {
  134. return null(i);
  135. }
  136. template<> inline i64
  137. sqlstmt_t::column(int i)
  138. {
  139. return integer(i);
  140. }
  141. template<> inline double
  142. sqlstmt_t::column(int i)
  143. {
  144. return real(i);
  145. }
  146. template<> inline std::string
  147. sqlstmt_t::column(int i)
  148. {
  149. return str(i);
  150. }
  151. template<> inline const char *
  152. sqlstmt_t::column(int i)
  153. {
  154. return c_str(i);
  155. }
  156. void sqlexec (sqlite3 *db, const char *fmt, ...);
  157. #endif /* !_SQLSTMT_H_ */