sqlite3.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /* =============================================================================
  2. *
  3. * Title: SQLite3 wrapper library
  4. * Author: Felix Niederwanger, 2017 <felix@feldspaten.org>
  5. * License: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
  6. * This C++ wrapper is intended to make access to sqlite3
  7. * more convenient
  8. * This file is a standalone
  9. * Link it with -lsqlite3
  10. *
  11. * =============================================================================
  12. */
  13. #ifndef _LAZY_SQLITE3_HPP_
  14. #define _LAZY_SQLITE3_HPP_
  15. #include <string>
  16. #include <sstream>
  17. #include <string.h>
  18. #include <sqlite3.h>
  19. namespace lazy {
  20. class SQLite3Cursor;
  21. class SQLite3 {
  22. private:
  23. std::string _filename;
  24. sqlite3 *db;
  25. public:
  26. SQLite3(const char* filename);
  27. virtual ~SQLite3();
  28. void close();
  29. void execute(const char* sql);
  30. void execute(const std::string &sql) { this->execute(sql.c_str()); }
  31. std::string filename() const { return this->_filename; }
  32. SQLite3Cursor cursor();
  33. };
  34. class SQLite3Cursor {
  35. private:
  36. sqlite3_stmt *res;
  37. sqlite3 *db;
  38. SQLite3Cursor(sqlite3 *db);
  39. public:
  40. SQLite3Cursor(SQLite3Cursor &&src); // Move constructor is allowed
  41. virtual ~SQLite3Cursor();
  42. void close();
  43. /** Prepare a SQL statement. Placeholders are '?'
  44. * Bind the placeholders with the corresponding bind methods
  45. * @throws const char* on error
  46. */
  47. void execute(const char* sql);
  48. void execute(const std::string &sql) { this->execute(sql.c_str()); }
  49. /** Bind integer value to the given statement */
  50. void bind(const int index, const int value);
  51. void bind(const int index, const long value);
  52. void bind(const int index, const float value) { this->bind(index, (double)value); }
  53. void bind(const int index, const double value);
  54. void bind(const int index, const char* value);
  55. void bind(const int index, const std::string &value) { this->bind(index, value.c_str()); }
  56. int fetchInt(const int column);
  57. long fetchLong(const int column);
  58. float fetchFloat(const int column);
  59. double fetchDouble(const int column);
  60. std::string fetchString(const int column);
  61. /** Fetch the next row, if available */
  62. bool next();
  63. friend class SQLite3;
  64. };
  65. SQLite3::SQLite3(const char* filename) {
  66. int rc = sqlite3_open(filename, &db);
  67. if(rc != SQLITE_OK) throw "Error opening database"; // fail early
  68. }
  69. SQLite3::~SQLite3() {
  70. this->close();
  71. }
  72. void SQLite3::close() {
  73. if(db != NULL) {
  74. sqlite3_close(db);
  75. db = NULL;
  76. }
  77. }
  78. void SQLite3::execute(const char* sql) {
  79. if(db == NULL) throw "Database closed";
  80. int rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
  81. if (rc != SQLITE_OK ) throw "Error executing sql";
  82. }
  83. SQLite3Cursor SQLite3::cursor() {
  84. SQLite3Cursor cursor(this->db);
  85. return cursor;
  86. }
  87. SQLite3Cursor::SQLite3Cursor(sqlite3 *db) {
  88. this->db = db;
  89. this->res = NULL;
  90. }
  91. SQLite3Cursor::SQLite3Cursor(SQLite3Cursor &&src) {
  92. this->res = src.res;
  93. src.res = NULL;
  94. }
  95. SQLite3Cursor::~SQLite3Cursor() {
  96. this->close();
  97. }
  98. void SQLite3Cursor::close() {
  99. if(this->res != NULL) {
  100. sqlite3_finalize(res);
  101. this->res = NULL;
  102. }
  103. }
  104. void SQLite3Cursor::execute(const char* sql) {
  105. this->close();
  106. int rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
  107. if (rc != SQLITE_OK) {
  108. if(res != NULL) sqlite3_finalize(res);
  109. throw "Error executing sql";
  110. }
  111. }
  112. void SQLite3Cursor::bind(const int index, const int value) {
  113. if(res == NULL) throw "Not prepared cursor";
  114. if (sqlite3_bind_int(res, index, value) != SQLITE_OK) throw "Error binding value";
  115. }
  116. void SQLite3Cursor::bind(const int index, const long value) {
  117. if(res == NULL) throw "Not prepared cursor";
  118. if (sqlite3_bind_int64(res, index, (sqlite3_int64)value) != SQLITE_OK) throw "Error binding value";
  119. }
  120. void SQLite3Cursor::bind(const int index, const double value) {
  121. if(res == NULL) throw "Not prepared cursor";
  122. if (sqlite3_bind_double(res, index, value) != SQLITE_OK) throw "Error binding value";
  123. }
  124. void SQLite3Cursor::bind(const int index, const char* value) {
  125. if(res == NULL) throw "Not prepared cursor";
  126. const int len = (int)strlen(value);
  127. if (sqlite3_bind_text(res, index, value, len, SQLITE_STATIC) != SQLITE_OK) throw "Error binding value";
  128. }
  129. bool SQLite3Cursor::next() {
  130. while(res != NULL) {
  131. int rc = sqlite3_step(this->res);
  132. if(rc == SQLITE_BUSY)
  133. continue; // XXX: Busy waiting
  134. else if(rc == SQLITE_ROW)
  135. return true;
  136. else if(rc == SQLITE_DONE)
  137. return false;
  138. else if(rc == SQLITE_ERROR)
  139. throw "Runtime error";
  140. else if(rc == SQLITE_MISUSE)
  141. throw "Misuse of routine";
  142. else
  143. throw "Inapropriate return code";
  144. }
  145. throw "Not prepared cursor";
  146. }
  147. int SQLite3Cursor::fetchInt(const int column) {
  148. if(this->res == NULL) throw "Not prepared cursor";
  149. return sqlite3_column_int(this->res, column);
  150. }
  151. long SQLite3Cursor::fetchLong(const int column) {
  152. if(this->res == NULL) throw "Not prepared cursor";
  153. return (long)sqlite3_column_int64(this->res, column);
  154. }
  155. float SQLite3Cursor::fetchFloat(const int column) {
  156. return (float)fetchDouble(column);
  157. }
  158. double SQLite3Cursor::fetchDouble(const int column) {
  159. if(this->res == NULL) throw "Not prepared cursor";
  160. return sqlite3_column_double(this->res, column);
  161. }
  162. std::string SQLite3Cursor::fetchString(const int column) {
  163. if(this->res == NULL) throw "Not prepared cursor";
  164. char *str = (char*)sqlite3_column_text(this->res, column);
  165. int size = sqlite3_column_bytes(this->res, column);
  166. std::stringstream ss;
  167. for(int i=0;i<size;i++) ss << str[i];
  168. return ss.str();
  169. }
  170. }
  171. #endif