* add compiled statement for batch inserting 100 occurrences at once * removed unnecessary primary key from component_access to get rid of additional index table * changed explicit check for existing symbols when injecting to implicit check in insert statement (insert or ignore) * improved performance of adding edges by replacing edge multi part index with in-memory-index * added in-memory-index for node table * added in-memory-index for local_symbol table * added in-memory-index for lource_location table * moved setting storage mode to SqliteIndexStorage, because storage modes are not used anywhere else. * don't store current mode as member because re-creating an existing index takes no time. * add getter for name of SqliteDatabaseIndex * removed unused method from persistent storage
296 lines
5.6 KiB
C++
296 lines
5.6 KiB
C++
#include "data/storage/sqlite/SqliteStorage.h"
|
|
|
|
#include "utility/file/FileSystem.h"
|
|
#include "utility/logging/logging.h"
|
|
#include "utility/TimeStamp.h"
|
|
#include "utility/utilityString.h"
|
|
|
|
SqliteStorage::SqliteStorage(const FilePath& dbFilePath)
|
|
: m_dbFilePath(dbFilePath.getCanonical())
|
|
{
|
|
if (!m_dbFilePath.getParentDirectory().empty() && !m_dbFilePath.getParentDirectory().exists())
|
|
{
|
|
FileSystem::createDirectory(m_dbFilePath.getParentDirectory());
|
|
}
|
|
|
|
m_database.open(utility::encodeToUtf8(m_dbFilePath.wstr()).c_str());
|
|
|
|
executeStatement("PRAGMA foreign_keys=ON;");
|
|
}
|
|
|
|
SqliteStorage::~SqliteStorage()
|
|
{
|
|
try
|
|
{
|
|
m_database.close();
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(e.errorMessage());
|
|
}
|
|
}
|
|
|
|
void SqliteStorage::setup()
|
|
{
|
|
executeStatement("PRAGMA foreign_keys=ON;");
|
|
setupMetaTable();
|
|
|
|
if (isEmpty() || !isIncompatible())
|
|
{
|
|
setupTables();
|
|
|
|
if (!m_precompiledStatementsInitialized)
|
|
{
|
|
setupPrecompiledStatements();
|
|
m_precompiledStatementsInitialized = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SqliteStorage::clear()
|
|
{
|
|
executeStatement("PRAGMA foreign_keys=OFF;");
|
|
clearMetaTable();
|
|
clearTables();
|
|
|
|
setup();
|
|
}
|
|
|
|
size_t SqliteStorage::getVersion() const
|
|
{
|
|
std::string storageVersionStr = getMetaValue("storage_version");
|
|
|
|
if (!storageVersionStr.empty())
|
|
{
|
|
return std::stoi(storageVersionStr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SqliteStorage::setVersion(size_t version)
|
|
{
|
|
insertOrUpdateMetaValue("storage_version", std::to_string(version));
|
|
}
|
|
|
|
void SqliteStorage::beginTransaction()
|
|
{
|
|
executeStatement("BEGIN TRANSACTION;");
|
|
}
|
|
|
|
void SqliteStorage::commitTransaction()
|
|
{
|
|
executeStatement("COMMIT TRANSACTION;");
|
|
}
|
|
|
|
void SqliteStorage::rollbackTransaction()
|
|
{
|
|
executeStatement("ROLLBACK TRANSACTION;");
|
|
}
|
|
|
|
void SqliteStorage::optimizeMemory() const
|
|
{
|
|
executeStatement("VACUUM;");
|
|
}
|
|
|
|
FilePath SqliteStorage::getDbFilePath() const
|
|
{
|
|
return m_dbFilePath;
|
|
}
|
|
|
|
bool SqliteStorage::isEmpty() const
|
|
{
|
|
return getVersion() <= 0;
|
|
}
|
|
|
|
bool SqliteStorage::isIncompatible() const
|
|
{
|
|
size_t storageVersion = getVersion();
|
|
if (isEmpty() || storageVersion != getStaticVersion())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SqliteStorage::setTime()
|
|
{
|
|
insertOrUpdateMetaValue("timestamp", TimeStamp::now().toString());
|
|
}
|
|
|
|
TimeStamp SqliteStorage::getTime() const
|
|
{
|
|
return TimeStamp(getMetaValue("timestamp"));
|
|
}
|
|
|
|
void SqliteStorage::setupMetaTable()
|
|
{
|
|
try
|
|
{
|
|
m_database.execDML(
|
|
"CREATE TABLE IF NOT EXISTS meta("
|
|
"id INTEGER, "
|
|
"key TEXT, "
|
|
"value TEXT, "
|
|
"PRIMARY KEY(id)"
|
|
");"
|
|
);
|
|
}
|
|
catch (CppSQLite3Exception& e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
|
|
throw(std::exception());
|
|
}
|
|
}
|
|
|
|
void SqliteStorage::clearMetaTable()
|
|
{
|
|
try
|
|
{
|
|
m_database.execDML("DROP TABLE IF EXISTS main.meta;");
|
|
}
|
|
catch (CppSQLite3Exception& e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
}
|
|
}
|
|
|
|
bool SqliteStorage::executeStatement(const std::string& statement) const
|
|
{
|
|
try
|
|
{
|
|
m_database.execDML(statement.c_str());
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SqliteStorage::executeStatement(CppSQLite3Statement& statement) const
|
|
{
|
|
try
|
|
{
|
|
statement.execDML();
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int SqliteStorage::executeStatementScalar(const std::string& statement, const int nullValue) const
|
|
{
|
|
int ret = 0;
|
|
try
|
|
{
|
|
ret = m_database.execScalar(statement.c_str(), nullValue);
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int SqliteStorage::executeStatementScalar(CppSQLite3Statement& statement, const int nullValue) const
|
|
{
|
|
int ret = 0;
|
|
try
|
|
{
|
|
CppSQLite3Query q = executeQuery(statement);
|
|
|
|
if (q.eof() || q.numFields() < 1)
|
|
{
|
|
char error[] = "Invalid scalar query";
|
|
throw CppSQLite3Exception(
|
|
CPPSQLITE_ERROR,
|
|
error,
|
|
false
|
|
);
|
|
}
|
|
|
|
ret = q.getIntField(0, nullValue);
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
CppSQLite3Query SqliteStorage::executeQuery(const std::string& statement) const
|
|
{
|
|
try
|
|
{
|
|
return m_database.execQuery(statement.c_str());
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
}
|
|
return CppSQLite3Query();
|
|
}
|
|
|
|
CppSQLite3Query SqliteStorage::executeQuery(CppSQLite3Statement& statement) const
|
|
{
|
|
try
|
|
{
|
|
return statement.execQuery();
|
|
}
|
|
catch (CppSQLite3Exception e)
|
|
{
|
|
LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage());
|
|
}
|
|
return CppSQLite3Query();
|
|
}
|
|
|
|
bool SqliteStorage::hasTable(const std::string& tableName) const
|
|
{
|
|
CppSQLite3Query q = executeQuery(
|
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';"
|
|
);
|
|
|
|
if (!q.eof())
|
|
{
|
|
return q.getStringField(0, "") == tableName;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string SqliteStorage::getMetaValue(const std::string& key) const
|
|
{
|
|
if (hasTable("meta"))
|
|
{
|
|
CppSQLite3Query q = executeQuery("SELECT value FROM meta WHERE key = '" + key + "';");
|
|
|
|
if (!q.eof())
|
|
{
|
|
return q.getStringField(0, "");
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void SqliteStorage::insertOrUpdateMetaValue(const std::string& key, const std::string& value)
|
|
{
|
|
CppSQLite3Statement stmt = m_database.compileStatement(std::string(
|
|
"INSERT OR REPLACE INTO meta(id, key, value) VALUES("
|
|
"(SELECT id FROM meta WHERE key = ?), ?, ?"
|
|
");"
|
|
).c_str());
|
|
|
|
stmt.bind(1, key.c_str());
|
|
stmt.bind(2, key.c_str());
|
|
stmt.bind(3, value.c_str());
|
|
executeStatement(stmt);
|
|
}
|