database.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * database.cpp
  3. *
  4. * Created on: Dec 4, 2015
  5. * Author: Philipp Hinz
  6. */
  7. #include <cstdio>
  8. #include <stdlib.h>
  9. #include <inttypes.h>
  10. #include <cstdarg>
  11. #include <cstring>
  12. #include <string>
  13. #include <stdexcept>
  14. #include <pthread.h>
  15. #include <sys/time.h>
  16. #include "sqlite/sqlite3.h"
  17. #include "global.h"
  18. #include "database.h"
  19. #include "logger.h"
  20. using namespace std;
  21. sqlite3 *db; /**< The database connector */
  22. /**
  23. * Helper function to allow the use of vsprintf() with a string
  24. * See: http://codereview.stackexchange.com/questions/52522/mimic-sprintf-with-stdstring-output
  25. */
  26. std::string string_vsprintf(const char* format, std::va_list args) {
  27. va_list tmp_args; //unfortunately you cannot consume a va_list twice
  28. va_copy(tmp_args, args); //so we have to copy it
  29. const int required_len = vsnprintf(nullptr, 0, format, tmp_args) + 1;
  30. va_end(tmp_args);
  31. std::string buf(required_len, '\0');
  32. if (std::vsnprintf(&buf[0], buf.size(), format, args) < 0) {
  33. throw std::runtime_error { "string_vsprintf encoding error" };
  34. }
  35. return buf;
  36. }
  37. /**
  38. * Allows the format of printf but returns a string
  39. * Source: http://codereview.stackexchange.com/questions/52522/mimic-sprintf-with-stdstring-output
  40. * @return printf formatted string
  41. * @param format input string as char array
  42. */
  43. std::string string_sprintf(const char* format, ...)
  44. __attribute__ ((format (printf, 1, 2)));
  45. std::string string_sprintf(const char* format, ...) {
  46. std::va_list args;
  47. va_start(args, format);
  48. std::string str { string_vsprintf(format, args) };
  49. va_end(args);
  50. return str;
  51. }
  52. static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
  53. int i;
  54. for (i = 0; i < argc; i++) {
  55. printf("%s = '%s'\n", azColName[i], argv[i] ? argv[i] : "NULL");
  56. }
  57. printf("\n");
  58. return 0;
  59. }
  60. /**
  61. * Opens and initializes a sqlite3 database connection
  62. * @return 0 on success
  63. */
  64. int sqlOpen() {
  65. int rc = sqlite3_open(SQL_DATABASE, &db);
  66. if (rc) {
  67. logger_error("Can't open database: %s\n", sqlite3_errmsg(db));
  68. sqlite3_close(db);
  69. return (1);
  70. }
  71. logger(V_BASIC, "Successfully opened SQLite connection to %s\n",
  72. SQL_DATABASE);
  73. return 0;
  74. }
  75. /**
  76. * Closes the database connection
  77. */
  78. void sqlClose() {
  79. sqlite3_close(db);
  80. logger(V_BASIC, "Closed SQLite connection.\n");
  81. }
  82. /**
  83. * Executes a SQL statement
  84. * @param *query SQL query string
  85. * @return 0 on success
  86. */
  87. int sqlExecute(string query) {
  88. char *zErrMsg = 0;
  89. int rc;
  90. struct timeval tv1, tv2;
  91. //pthread_mutex_lock(&mutex);
  92. logger(V_SQL, "Executing SQL Query: %s\n", query.c_str());
  93. gettimeofday(&tv1, NULL);
  94. rc = sqlite3_exec(db, query.c_str(), NULL, 0, &zErrMsg);
  95. gettimeofday(&tv2, NULL);
  96. if (verbose == V_SQL)
  97. printf("Time taken in execution = %f seconds\n",
  98. (double) (tv2.tv_usec - tv1.tv_usec) / 1000000
  99. + (double) (tv2.tv_sec - tv1.tv_sec));
  100. //pthread_mutex_unlock(&mutex);
  101. if (rc != SQLITE_OK) {
  102. logger_error("SQL error (%d): %s\n", rc, zErrMsg);
  103. sqlite3_free(zErrMsg);
  104. return rc;
  105. }
  106. return 0;
  107. }
  108. int sqlExecute2(char *query) {
  109. char *zErrMsg = 0;
  110. int rc;
  111. logger(V_SQL, "Executing SQL Query: %s\n", query);
  112. rc = sqlite3_exec(db, query, &callback, 0, &zErrMsg);
  113. if (rc != SQLITE_OK) {
  114. logger_error("SQL error (%d): %s\n", rc, zErrMsg);
  115. sqlite3_free(zErrMsg);
  116. return rc;
  117. }
  118. return 0;
  119. }
  120. /**
  121. * Sets up the database and creates the needed structure
  122. * @return 0 on success
  123. */
  124. int sqlSetup() {
  125. sqlExecute("CREATE TABLE IF NOT EXISTS config "
  126. "(id INTEGER PRIMARY KEY, "
  127. "value NUMERIC);");
  128. return 0;
  129. }
  130. /**
  131. * Reads a configuration key from the database
  132. * @param id Config ID key
  133. * @return value as integer (up to 64bit), 0 for not found
  134. */
  135. uint64_t sqlGetConf(config_key_t id) {
  136. sqlite3_stmt *stmt;
  137. uint64_t out;
  138. string query = string_sprintf("SELECT id, value FROM config "
  139. "WHERE id = %d", id);
  140. int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
  141. if (rc != SQLITE_OK) {
  142. logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db));
  143. sqlite3_finalize(stmt);
  144. return 0;
  145. }
  146. rc = sqlite3_step(stmt);
  147. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  148. logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db));
  149. sqlite3_finalize(stmt);
  150. return 0;
  151. }
  152. if (rc == SQLITE_DONE) { // no results
  153. sqlite3_finalize(stmt);
  154. return 0;
  155. }
  156. out = sqlite3_column_int64(stmt, 1);
  157. sqlite3_finalize(stmt);
  158. return out;
  159. }
  160. /**
  161. * Saves a configuration key to the database
  162. * @param id Config ID key
  163. * @param value Integer value
  164. * @return 0 on success
  165. */
  166. int sqlSetConf(config_key_t id, uint64_t value) {
  167. int rc = sqlExecute(string_sprintf("REPLACE INTO config (id, value) "
  168. "VALUES (%d, %lld);", id, value));
  169. if (rc != SQLITE_OK)
  170. return EXIT_FAILURE;
  171. return EXIT_SUCCESS;
  172. }
  173. /**
  174. * Logs the flow curve
  175. * @param sweep identification for the curve
  176. * @param flow the cumulative measured amount
  177. * @param deltaT time between the last flow interrupt and the current one
  178. */
  179. int sqlLogFlow(uint64_t sweep, uint64_t flow, uint64_t deltaT) {
  180. int rc = sqlExecute(string_sprintf("INSERT INTO flowLog (sweep, flow, timestamp) "
  181. "VALUES (%lld, %lld, %lld);", sweep, flow, deltaT));
  182. if (rc != SQLITE_OK)
  183. return EXIT_FAILURE;
  184. return EXIT_SUCCESS;
  185. }
  186. /**
  187. * Converts the GUID from int to char array
  188. * @param *guid Pointer to the uint8_t GUID
  189. * @return pointer to the converted string
  190. */
  191. char *inttochar(uint8_t *guid) {
  192. char *out = new char[9];
  193. for (int i = 0; i < 8; i++) {
  194. out[i] = (char) guid[i];
  195. }
  196. out[8] = '\0';
  197. return out;
  198. }
  199. /**
  200. * Converts the GUID from char to int array
  201. * @param *guid Pointer to the char GUID
  202. * @return pointer to the converted int array
  203. */
  204. uint8_t *chartoint(const unsigned char *guid) {
  205. uint8_t *out = new uint8_t[8];
  206. for (int i = 0; i < 8; i++) {
  207. out[i] = (uint8_t) guid[i];
  208. }
  209. return out;
  210. }
  211. /**
  212. * Converts the GUID from int64 to int8 array
  213. * @param guid 64bit GUID
  214. * @return pointer to the converted int array
  215. */
  216. uint8_t *int64to8bit(sqlite_int64 guid) {
  217. uint8_t *out = new uint8_t[8];
  218. for (int i = 7; i >= 0; i--) {
  219. out[i] = guid & 0xff;
  220. guid = guid >> 8;
  221. }
  222. return out;
  223. }
  224. sqlite_int64 int8to64bit(uint8_t *guid) {
  225. sqlite_int64 out = 0;
  226. for (int i = 0; i < 8; i++) {
  227. out |= guid[i] << (8 * (7 - i));
  228. }
  229. return out;
  230. }
  231. void sqltest() {
  232. sqlSetup();
  233. //sqlExecute2("SELECT * FROM nodes;");
  234. }