/* * database.cpp * * Created on: Dec 4, 2015 * Author: Philipp Hinz */ #include #include #include #include #include #include #include #include #include #include "sqlite/sqlite3.h" #include "global.h" #include "database.h" #include "logger.h" using namespace std; sqlite3 *db; /**< The database connector */ /** * Helper function to allow the use of vsprintf() with a string * See: http://codereview.stackexchange.com/questions/52522/mimic-sprintf-with-stdstring-output */ std::string string_vsprintf(const char* format, std::va_list args) { va_list tmp_args; //unfortunately you cannot consume a va_list twice va_copy(tmp_args, args); //so we have to copy it const int required_len = vsnprintf(nullptr, 0, format, tmp_args) + 1; va_end(tmp_args); std::string buf(required_len, '\0'); if (std::vsnprintf(&buf[0], buf.size(), format, args) < 0) { throw std::runtime_error { "string_vsprintf encoding error" }; } return buf; } /** * Allows the format of printf but returns a string * Source: http://codereview.stackexchange.com/questions/52522/mimic-sprintf-with-stdstring-output * @return printf formatted string * @param format input string as char array */ std::string string_sprintf(const char* format, ...) __attribute__ ((format (printf, 1, 2))); std::string string_sprintf(const char* format, ...) { std::va_list args; va_start(args, format); std::string str { string_vsprintf(format, args) }; va_end(args); return str; } static int callback(void *NotUsed, int argc, char **argv, char **azColName) { int i; for (i = 0; i < argc; i++) { printf("%s = '%s'\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } /** * Opens and initializes a sqlite3 database connection * @return 0 on success */ int sqlOpen() { int rc = sqlite3_open(SQL_DATABASE, &db); if (rc) { logger_error("Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return (1); } logger(V_BASIC, "Successfully opened SQLite connection to %s\n", SQL_DATABASE); return 0; } /** * Closes the database connection */ void sqlClose() { sqlite3_close(db); logger(V_BASIC, "Closed SQLite connection.\n"); } /** * Executes a SQL statement * @param *query SQL query string * @return 0 on success */ int sqlExecute(string query) { char *zErrMsg = 0; int rc; struct timeval tv1, tv2; //pthread_mutex_lock(&mutex); logger(V_SQL, "Executing SQL Query: %s\n", query.c_str()); gettimeofday(&tv1, NULL); rc = sqlite3_exec(db, query.c_str(), NULL, 0, &zErrMsg); gettimeofday(&tv2, NULL); if (verbose == V_SQL) printf("Time taken in execution = %f seconds\n", (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 + (double) (tv2.tv_sec - tv1.tv_sec)); //pthread_mutex_unlock(&mutex); if (rc != SQLITE_OK) { logger_error("SQL error (%d): %s\n", rc, zErrMsg); sqlite3_free(zErrMsg); return rc; } return 0; } int sqlExecute2(char *query) { char *zErrMsg = 0; int rc; logger(V_SQL, "Executing SQL Query: %s\n", query); rc = sqlite3_exec(db, query, &callback, 0, &zErrMsg); if (rc != SQLITE_OK) { logger_error("SQL error (%d): %s\n", rc, zErrMsg); sqlite3_free(zErrMsg); return rc; } return 0; } /** * Sets up the database and creates the needed structure * @return 0 on success */ int sqlSetup() { sqlExecute("CREATE TABLE IF NOT EXISTS config " "(id INTEGER PRIMARY KEY, " "value NUMERIC);"); return 0; } /** * Reads a configuration key from the database * @param id Config ID key * @return value as integer (up to 64bit), 0 for not found */ uint64_t sqlGetConf(config_key_t id) { sqlite3_stmt *stmt; uint64_t out; string query = string_sprintf("SELECT id, value FROM config " "WHERE id = %d", id); int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL); if (rc != SQLITE_OK) { logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db)); sqlite3_finalize(stmt); return 0; } rc = sqlite3_step(stmt); if (rc != SQLITE_ROW && rc != SQLITE_DONE) { logger_error("SQL error (%d): %s\n", rc, sqlite3_errmsg(db)); sqlite3_finalize(stmt); return 0; } if (rc == SQLITE_DONE) { // no results sqlite3_finalize(stmt); return 0; } out = sqlite3_column_int64(stmt, 1); sqlite3_finalize(stmt); return out; } /** * Saves a configuration key to the database * @param id Config ID key * @param value Integer value * @return 0 on success */ int sqlSetConf(config_key_t id, uint64_t value) { int rc = sqlExecute(string_sprintf("REPLACE INTO config (id, value) " "VALUES (%d, %lld);", id, value)); if (rc != SQLITE_OK) return EXIT_FAILURE; return EXIT_SUCCESS; } /** * Logs the flow curve * @param sweep identification for the curve * @param flow the cumulative measured amount * @param deltaT time between the last flow interrupt and the current one */ int sqlLogFlow(uint64_t sweep, uint64_t flow, uint64_t deltaT) { int rc = sqlExecute(string_sprintf("INSERT INTO flowLog (sweep, flow, timestamp) " "VALUES (%lld, %lld, %lld);", sweep, flow, deltaT)); if (rc != SQLITE_OK) return EXIT_FAILURE; return EXIT_SUCCESS; } /** * Converts the GUID from int to char array * @param *guid Pointer to the uint8_t GUID * @return pointer to the converted string */ char *inttochar(uint8_t *guid) { char *out = new char[9]; for (int i = 0; i < 8; i++) { out[i] = (char) guid[i]; } out[8] = '\0'; return out; } /** * Converts the GUID from char to int array * @param *guid Pointer to the char GUID * @return pointer to the converted int array */ uint8_t *chartoint(const unsigned char *guid) { uint8_t *out = new uint8_t[8]; for (int i = 0; i < 8; i++) { out[i] = (uint8_t) guid[i]; } return out; } /** * Converts the GUID from int64 to int8 array * @param guid 64bit GUID * @return pointer to the converted int array */ uint8_t *int64to8bit(sqlite_int64 guid) { uint8_t *out = new uint8_t[8]; for (int i = 7; i >= 0; i--) { out[i] = guid & 0xff; guid = guid >> 8; } return out; } sqlite_int64 int8to64bit(uint8_t *guid) { sqlite_int64 out = 0; for (int i = 0; i < 8; i++) { out |= guid[i] << (8 * (7 - i)); } return out; } void sqltest() { sqlSetup(); //sqlExecute2("SELECT * FROM nodes;"); }