// // EyeDB.cpp // ionuCommon // // Created by Frank Vernon on 1/16/14. // Copyright (c) 2013-2014 IONU Security. All rights reserved. // #include "eyedb.h" #include "eyelog.h" #include "eyeutils.h" #include #include namespace sequencelogic { //MARK: EyeDB EyeDB::EyeDB() :_db(NULL), _db_open(false), _busy_timeout_seconds(0.0) { } EyeDB::~EyeDB() { close(); } bool EyeDB::open(const char * filepath) { close(); if (sequencelogic::IsValidFilename(filepath)) { int result = sqlite3_open_v2 (filepath, &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); if (result == SQLITE_OK) { _db_open = true; busyTimeout(_busy_timeout_seconds); } else { IONUDEBUG ("EyeDB::open open/create failed - %s (%d)", filepath, result); } } return _db_open; } void EyeDB::close() { if (_db != NULL) { sqlite3_close_v2(_db); _db = NULL; } _db_open = false; } void EyeDB::busyTimeout(double timeoutSeconds) { _busy_timeout_seconds = timeoutSeconds; if (_db != NULL) { sqlite3_busy_timeout(_db, (int)(_busy_timeout_seconds*1000.0)); } } std::string EyeDB::filePath() { std::string result = sqlite3_db_filename(_db, "main"); return result; } bool EyeDB::executeQuery(const std::string & query) { char* errmsg = NULL; int result = sqlite3_exec(_db, query.c_str(), NULL, NULL, &errmsg); if (result != SQLITE_OK) { IONUDEBUG ("EyeDB::executeQuery() failed - %s (%d)", errmsg, result); return false; } return true; } MAP_VECTOR EyeDB::fetchResults(const statement & statement) { MAP_VECTOR result; while(statement.step() == SQLITE_ROW) { //might want to move count/column/text/blob to statement object int columns = sqlite3_data_count(statement); STRING_STRING_MAP rowMap; for (int i = 0; i < columns; ++i) { const char * key = sqlite3_column_name(statement, i); int type = sqlite3_column_type(statement, i); switch (type) { case SQLITE_INTEGER: case SQLITE_FLOAT: case SQLITE_TEXT: { const unsigned char * value = sqlite3_column_text(statement, i); std::size_t value_length = sqlite3_column_bytes(statement, i); rowMap[std::string(key)] = std::string((const char *)value, value_length); } break; case SQLITE_BLOB: { const void * value = sqlite3_column_blob(statement, i); std::size_t value_length = sqlite3_column_bytes(statement, i); rowMap[std::string(key)] = std::string((const char*)value, value_length); } break; case SQLITE_NULL: { rowMap[std::string(key)] = std::string(); } break; default: IONUDEBUG ("EyeDB::fetchResults() Unexpected type: %d", type); break; } } result.push_back(rowMap); } return result; } //MARK: transaction transaction::transaction(EyeDB & db) :_commit(false), _db(db) { sqlite3_exec(_db, "BEGIN", 0, 0, 0); } transaction::~transaction() { if (_commit) { sqlite3_exec(_db, "COMMIT", 0, 0, 0); } else { sqlite3_exec(_db, "ROLLBACK", 0, 0, 0); } } void transaction::commit() { _commit = true; } //MARK: savepoint savepoint::savepoint(EyeDB & db, const char * savepoint) :_commit(true), _db(db), _savepoint(savepoint) { std::stringstream sql; sql << "SAVEPOINT" << " " << _savepoint; sqlite3_exec(_db, sql.str().c_str(), 0, 0, 0); } savepoint::~savepoint() { std::stringstream sql; if (_commit) { sql << "RELEASE SAVEPOINT" << " " << _savepoint; } else { sql << "ROLLBACK TO SAVEPOINT" << " " << _savepoint; } sqlite3_exec(_db, sql.str().c_str(), 0, 0, 0); } void savepoint::commit() { _commit = true; } //MARK: statement statement::statement() :stmt(NULL), prepared(false) { } statement::statement(EyeDB & db, const std::string & query) :stmt(NULL), prepared(false) { prepare(db, query); } statement::~statement() { finalize(); } bool statement::prepare(EyeDB & db, const std::string & query) { int result = sqlite3_prepare_v2 (db, query.c_str(), (int)query.length(), &stmt, 0); prepared = result == SQLITE_OK; if (!prepared) { IONUDEBUG ("statement::prepare() prepare failed: %s", query.c_str()); } return prepared; } bool statement::bind(int position, const std::string & text) { if (!prepared) return false; int result = sqlite3_bind_text(stmt, position, text.c_str(), -1, SQLITE_STATIC); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(text) - failed %d", result); return false; } return true; } bool statement::bind(int position, const void * blob, int blobLength) { if (!prepared) return false; int result = sqlite3_bind_blob(stmt, position, blob, blobLength, SQLITE_TRANSIENT); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(blob) - failed %d", result); return false; } return true; } bool statement::bind(int position, int integer) { if (!prepared) return false; int result = sqlite3_bind_int(stmt, position, integer); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(int) - failed %d", result); return false; } return true; } bool statement::bind(int position, double dbl) { if (!prepared) return false; int result = sqlite3_bind_double(stmt, position, dbl); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(dbl) - failed %d", result); return false; } return true; } bool statement::bind(int position, sqlite3_int64 integer64) { if (!prepared) return false; int result = sqlite3_bind_int64(stmt, position, integer64); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(int64) - failed %d", result); return false; } return true; } bool statement::bind(int position, const sqlite3_value * value) { if (!prepared) return false; int result = sqlite3_bind_value(stmt, position, value); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(value) - failed %d", result); return false; } return true; } bool statement::bind_null(int position) { if (!prepared) return false; int result = sqlite3_bind_null(stmt, position); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(NULL) - failed %d", result); return false; } return true; } bool statement::bind_zeroblob(int position, int length) { if (!prepared) return false; int result = sqlite3_bind_zeroblob(stmt, position, length); if (result != SQLITE_OK) { IONUDEBUG ("statement::bind(NULL) - failed %d", result); return false; } return true; } bool statement::clear_bindings() const { int result = sqlite3_clear_bindings(stmt); if (result != SQLITE_OK) { IONUDEBUG ("statement::clear_bindings() - failed %d", result); return false; } return true; } int statement::step() const { if (!prepared) return false; return sqlite3_step(stmt); } bool statement::reset() const { if (!prepared) return false; int result = sqlite3_reset(stmt); if (result != SQLITE_OK) { IONUDEBUG ("statement::reset() - failed %d", result); return false; } return true; } void statement::finalize() { if (stmt != NULL) { sqlite3_finalize(stmt); stmt = NULL; } } bool statement::isPrepared() { return prepared; } int statement::columnType(int column) { return sqlite3_column_type(stmt, column); } double statement::columnBytesDouble(int column) { return sqlite3_column_double(stmt, column); } int statement::columnBytesInt(int column) { return sqlite3_column_bytes(stmt, column); } int statement::columnBytesInt16(int column) { return sqlite3_column_bytes16(stmt, column); } const void * statement::columnBlob(int column) { return sqlite3_column_blob(stmt, column); } int statement::columnInt(int column) { return sqlite3_column_int(stmt, column); } sqlite_int64 statement::columnInt64(int column) { return sqlite3_column_int64(stmt, column); } const unsigned char * statement::columnText(int column) { return sqlite3_column_text(stmt, column); } sqlite3_value * statement::columnValue(int column) { return sqlite3_column_value(stmt, column); } const void * statement::columnText16(int column) { return sqlite3_column_text16(stmt, column); } //MARK: PragmaAccess PragmaAccess::PragmaAccess(EyeDB & db) :_db(db) { } std::string PragmaAccess::get(const std::string &pragma) { std::string result; std::stringstream query; query << "PRAGMA " << pragma; statement statement(_db, query.str()); if (statement.isPrepared()) { MAP_VECTOR results = _db.fetchResults(statement); for (STRING_STRING_MAP & row : results) { for (auto column: row) { if (result.length() > 0) { result += ", "; } result += column.first + "=" + column.second; } } } return result; } bool PragmaAccess::set(const std::string &pragma, const std::string &value) { std::stringstream query; query << "PRAGMA " << pragma << " = " << value; return _db.executeQuery(query.str()); } }