477 lines
12 KiB
C++
477 lines
12 KiB
C++
|
|
//
|
||
|
|
// 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 <assert.h>
|
||
|
|
#include <sstream>
|
||
|
|
|
||
|
|
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());
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|