database.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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 nodes "
  126. "(id INTEGER PRIMARY KEY ASC AUTOINCREMENT, "
  127. "guid INTEGER UNIQUE, "
  128. "term INTEGER, "
  129. "terminal NUMERIC, "
  130. "devclass INTEGER, "
  131. "devtype INTEGER, "
  132. "hw INTEGER, "
  133. "fwmajor INTEGER, "
  134. "fwminor INTEGER, "
  135. "lastseen INTEGER, "
  136. "tableversion INTEGER, "
  137. "clockspeed INTEGER, "
  138. "voltage NUMERIC);");
  139. sqlExecute("CREATE TABLE IF NOT EXISTS config "
  140. "(id INTEGER PRIMARY KEY, "
  141. "value NUMERIC);");
  142. sqlExecute("CREATE TABLE IF NOT EXISTS monitorlog "
  143. "(id INTEGER PRIMARY KEY ASC AUTOINCREMENT, "
  144. "time NUMERIC, "
  145. "node INTEGER, "
  146. "type INTEGER, "
  147. "value NUMERIC, "
  148. "weight INTEGER);");
  149. sqlExecute("CREATE TABLE IF NOT EXISTS counters "
  150. "(id INTEGER PRIMARY KEY ASC, "
  151. "por INTEGER, "
  152. "wdr INTEGER, "
  153. "bodr INTEGER, "
  154. "er INTEGER, "
  155. "asc INTEGER, "
  156. "uptime INTEGER, "
  157. "rxerr INTEGER, "
  158. "txerr INTEGER, "
  159. "rx INTEGER, "
  160. "tx INTEGER);");
  161. return 0;
  162. }
  163. /**
  164. * Reads a configuration key from the database
  165. * @param id Config ID key
  166. * @return value as integer (up to 64bit), 0 for not found
  167. */
  168. uint64_t sqlGetConf(config_key_t id) {
  169. sqlite3_stmt *stmt;
  170. uint64_t out;
  171. string query = string_sprintf("SELECT id, value FROM config "
  172. "WHERE id = %d", id);
  173. int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
  174. if (rc != SQLITE_OK) {
  175. logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db));
  176. sqlite3_finalize(stmt);
  177. return 0;
  178. }
  179. rc = sqlite3_step(stmt);
  180. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  181. logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db));
  182. sqlite3_finalize(stmt);
  183. return 0;
  184. }
  185. if (rc == SQLITE_DONE) { // no results
  186. sqlite3_finalize(stmt);
  187. return 0;
  188. }
  189. out = sqlite3_column_int64(stmt, 1);
  190. sqlite3_finalize(stmt);
  191. return out;
  192. }
  193. /**
  194. * Saves a configuration key to the database
  195. * @param id Config ID key
  196. * @param value Integer value
  197. * @return 0 on success
  198. */
  199. int sqlSetConf(config_key_t id, uint64_t value) {
  200. int rc = sqlExecute(string_sprintf("REPLACE INTO config (id, value) "
  201. "VALUES (%d, %lld);", id, value));
  202. if (rc != SQLITE_OK)
  203. return EXIT_FAILURE;
  204. return EXIT_SUCCESS;
  205. }
  206. /**
  207. * Converts the GUID from int to char array
  208. * @param *guid Pointer to the uint8_t GUID
  209. * @return pointer to the converted string
  210. */
  211. char *inttochar(uint8_t *guid) {
  212. char *out = new char[9];
  213. for (int i = 0; i < 8; i++) {
  214. out[i] = (char) guid[i];
  215. }
  216. out[8] = '\0';
  217. return out;
  218. }
  219. /**
  220. * Converts the GUID from char to int array
  221. * @param *guid Pointer to the char GUID
  222. * @return pointer to the converted int array
  223. */
  224. uint8_t *chartoint(const unsigned char *guid) {
  225. uint8_t *out = new uint8_t[8];
  226. for (int i = 0; i < 8; i++) {
  227. out[i] = (uint8_t) guid[i];
  228. }
  229. return out;
  230. }
  231. /**
  232. * Converts the GUID from int64 to int8 array
  233. * @param guid 64bit GUID
  234. * @return pointer to the converted int array
  235. */
  236. uint8_t *int64to8bit(sqlite_int64 guid) {
  237. uint8_t *out = new uint8_t[8];
  238. for (int i = 7; i >= 0; i--) {
  239. out[i] = guid & 0xff;
  240. guid = guid >> 8;
  241. }
  242. return out;
  243. }
  244. sqlite_int64 int8to64bit(uint8_t *guid) {
  245. sqlite_int64 out = 0;
  246. for (int i = 0; i < 8; i++) {
  247. out |= guid[i] << (8 * (7 - i));
  248. }
  249. return out;
  250. }
  251. void sqltest() {
  252. sqlSetup();
  253. //sqlExecute2("SELECT * FROM nodes;");
  254. }