/* * Copyright 2018 Coati Software KG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "DatabaseStorage.h" #include #include "NodeKind.h" #include "SourcetrailException.h" #include "StorageFile.h" #include "StorageNode.h" #include "StorageSymbol.h" #include "utility.h" #include "version.h" namespace sourcetrail { // --- Public Interface --- int DatabaseStorage::getSupportedDatabaseVersion() { return DATABASE_VERSION; } std::unique_ptr DatabaseStorage::openDatabase(const std::string& dbFilePath) { try { std::unique_ptr storage = std::unique_ptr(new DatabaseStorage()); storage->m_database.open(dbFilePath.c_str()); storage->executeStatement("PRAGMA foreign_keys=ON;"); return std::move(storage); } catch (CppSQLite3Exception e) { throw SourcetrailException(e.errorMessage()); } } DatabaseStorage::~DatabaseStorage() { clearPrecompiledStatements(); m_database.close(); } void DatabaseStorage::setupDatabase() { executeStatement("PRAGMA foreign_keys=ON;"); if (!isCompatible()) { throw SourcetrailException("Unable to setup database tables because database is not compatible."); } setupTables(); setupIndices(); setupPrecompiledStatements(); insertOrUpdateMetaValue("storage_version", std::to_string(getSupportedDatabaseVersion())); } void DatabaseStorage::clearDatabase() { executeStatement("PRAGMA foreign_keys=OFF;"); clearPrecompiledStatements(); clearTables(); setupDatabase(); } void DatabaseStorage::setProjectSettingsText(const std::string& text) { insertOrUpdateMetaValue("project_settings", text); } bool DatabaseStorage::isEmpty() const { const std::string tableName = "meta"; CppSQLite3Query q = executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';"); if (!q.eof()) { return q.getStringField(0, "") == tableName; } return true; } bool DatabaseStorage::isCompatible() const { if (isEmpty()) { return true; } return getLoadedDatabaseVersion() == getSupportedDatabaseVersion(); } int DatabaseStorage::getLoadedDatabaseVersion() const { if (isEmpty()) { throw SourcetrailException("Unable to determine version of an empty database."); } CppSQLite3Query q = executeQuery("SELECT value FROM meta WHERE key = 'storage_version';"); if (!q.eof()) { return std::stoi(q.getStringField(0, "0")); } return 0; } void DatabaseStorage::beginTransaction() { executeStatement("BEGIN TRANSACTION;"); } void DatabaseStorage::commitTransaction() { executeStatement("COMMIT TRANSACTION;"); } void DatabaseStorage::rollbackTransaction() { executeStatement("ROLLBACK TRANSACTION;"); } void DatabaseStorage::optimizeDatabaseMemory() { executeStatement("VACUUM;"); } int DatabaseStorage::addElementComponent(const StorageElementComponentData& storageElementComponentData) { m_insertElementComponentStatement.bind(1, storageElementComponentData.elementId); m_insertElementComponentStatement.bind(2, storageElementComponentData.componentKind); m_insertElementComponentStatement.bind(3, storageElementComponentData.data.c_str()); executeStatement(m_insertElementComponentStatement); const int id = static_cast(m_database.lastRowId()); m_insertElementComponentStatement.reset(); return id; } int DatabaseStorage::addNode(const StorageNodeData& storageNodeData) { int id = 0; { m_findNodeStatement.bind(1, storageNodeData.serializedName.c_str()); CppSQLite3Query q = executeQuery(m_findNodeStatement); if (!q.eof()) { id = q.getIntField(0, 0); } m_findNodeStatement.reset(); } // FIXME: update node nodeKind here if (id == 0) { id = insertElement(); m_insertNodeStatement.bind(1, id); m_insertNodeStatement.bind(2, storageNodeData.nodeKind); m_insertNodeStatement.bind(3, storageNodeData.serializedName.c_str()); executeStatement(m_insertNodeStatement); m_insertNodeStatement.reset(); } return id; } void DatabaseStorage::addSymbol(const StorageSymbol& storageSymbol) { m_insertSymbolStatement.bind(1, storageSymbol.id); m_insertSymbolStatement.bind(2, storageSymbol.definitionKind); executeStatement(m_insertSymbolStatement); m_insertSymbolStatement.reset(); } void DatabaseStorage::addFile(const StorageFile& storageFile) { { m_findFileStatement.bind(1, storageFile.id); CppSQLite3Query q = executeQuery(m_findFileStatement); bool exists = !q.eof(); m_findFileStatement.reset(); if (exists) { return; } } std::string content = ""; if (utility::getFileExists(storageFile.filePath)) { content = utility::getFileContent(storageFile.filePath); } const int lineCount = utility::getLineCount(content); { m_insertFileStatement.bind(1, storageFile.id); m_insertFileStatement.bind(2, storageFile.filePath.c_str()); m_insertFileStatement.bind(3, storageFile.languageIdentifier.c_str()); m_insertFileStatement.bind(4, storageFile.modificationTime.c_str()); m_insertFileStatement.bind(5, storageFile.indexed); m_insertFileStatement.bind(6, storageFile.complete); m_insertFileStatement.bind(7, lineCount); executeStatement(m_insertFileStatement); m_insertFileStatement.reset(); } if (!content.empty()) { m_insertFileContentStatement.bind(1, storageFile.id); m_insertFileContentStatement.bind(2, content.c_str()); executeStatement(m_insertFileContentStatement); m_insertFileContentStatement.reset(); } } int DatabaseStorage::addEdge(const StorageEdgeData& storageEdgeData) { int id = 0; { m_findEdgeStatement.bind(1, storageEdgeData.sourceNodeId); m_findEdgeStatement.bind(2, storageEdgeData.targetNodeId); m_findEdgeStatement.bind(3, storageEdgeData.edgeKind); CppSQLite3Query q = executeQuery(m_findEdgeStatement); if (!q.eof()) { id = q.getIntField(0, 0); } m_findEdgeStatement.reset(); } if (id == 0) { id = insertElement(); m_insertEdgeStatement.bind(1, id); m_insertEdgeStatement.bind(2, storageEdgeData.edgeKind); m_insertEdgeStatement.bind(3, storageEdgeData.sourceNodeId); m_insertEdgeStatement.bind(4, storageEdgeData.targetNodeId); executeStatement(m_insertEdgeStatement); m_insertEdgeStatement.reset(); } return id; } int DatabaseStorage::addLocalSymbol(const StorageLocalSymbolData& storageLocalSymbolData) { int id = 0; { m_findLocalSymbolStmt.bind(1, storageLocalSymbolData.name.c_str()); CppSQLite3Query q = executeQuery(m_findLocalSymbolStmt); if (!q.eof()) { id = q.getIntField(0, 0); } m_findLocalSymbolStmt.reset(); } if (id == 0) { id = insertElement(); m_insertLocalSymbolStmt.bind(1, id); m_insertLocalSymbolStmt.bind(2, storageLocalSymbolData.name.c_str()); executeStatement(m_insertLocalSymbolStmt); m_insertLocalSymbolStmt.reset(); } return id; } int DatabaseStorage::addSourceLocation(const StorageSourceLocationData& storageSourceLocationData) { int id = 0; { m_findSourceLocationStmt.bind(1, storageSourceLocationData.fileNodeId); m_findSourceLocationStmt.bind(2, storageSourceLocationData.startLineNumber); m_findSourceLocationStmt.bind(3, storageSourceLocationData.startColumnNumber); m_findSourceLocationStmt.bind(4, storageSourceLocationData.endLineNumber); m_findSourceLocationStmt.bind(5, storageSourceLocationData.endColumnNumber); m_findSourceLocationStmt.bind(6, storageSourceLocationData.locationKind); CppSQLite3Query q = executeQuery(m_findSourceLocationStmt); if (!q.eof()) { id = q.getIntField(0, 0); } m_findSourceLocationStmt.reset(); } if (id == 0) { m_insertSourceLocationStmt.bind(1, storageSourceLocationData.fileNodeId); m_insertSourceLocationStmt.bind(2, storageSourceLocationData.startLineNumber); m_insertSourceLocationStmt.bind(3, storageSourceLocationData.startColumnNumber); m_insertSourceLocationStmt.bind(4, storageSourceLocationData.endLineNumber); m_insertSourceLocationStmt.bind(5, storageSourceLocationData.endColumnNumber); m_insertSourceLocationStmt.bind(6, storageSourceLocationData.locationKind); executeStatement(m_insertSourceLocationStmt); id = static_cast(m_database.lastRowId()); m_insertSourceLocationStmt.reset(); } return id; } void DatabaseStorage::addOccurrence(const StorageOccurrence& storageOccurrence) { m_insertOccurenceStmt.bind(1, storageOccurrence.elementId); m_insertOccurenceStmt.bind(2, storageOccurrence.sourceLocationId); executeStatement(m_insertOccurenceStmt); m_insertOccurenceStmt.reset(); } int DatabaseStorage::addError(const StorageErrorData& storageErrorData) { int id = 0; { m_findErrorStatement.bind(1, storageErrorData.message.c_str()); m_findErrorStatement.bind(2, storageErrorData.fatal); CppSQLite3Query q = executeQuery(m_findErrorStatement); if (!q.eof() && q.numFields() > 0) { id = q.getIntField(0, -1); } m_findErrorStatement.reset(); } if (id == 0) { id = insertElement(); m_insertErrorStatement.bind(1, id); m_insertErrorStatement.bind(2, storageErrorData.message.c_str()); m_insertErrorStatement.bind(3, storageErrorData.fatal); m_insertErrorStatement.bind(4, storageErrorData.indexed); m_insertErrorStatement.bind(5, storageErrorData.translationUnit.c_str()); executeStatement(m_insertErrorStatement); id = static_cast(m_database.lastRowId()); m_insertErrorStatement.reset(); } return id; } void DatabaseStorage::setNodeType(int nodeId, int nodeType) { m_setNodeTypeStmt.bind(1, nodeType); m_setNodeTypeStmt.bind(2, nodeId); executeStatement(m_setNodeTypeStmt); m_setNodeTypeStmt.reset(); } void DatabaseStorage::setFileLanguage(int fileId, const std::string& languageIdentifier) { m_setFileLanguageStmt.bind(1, languageIdentifier.c_str()); m_setFileLanguageStmt.bind(2, fileId); executeStatement(m_setFileLanguageStmt); m_setFileLanguageStmt.reset(); } // --- Private Interface --- void DatabaseStorage::setupTables() { executeStatement( "CREATE TABLE IF NOT EXISTS meta(" " id INTEGER, " " key TEXT, " " value TEXT, " " PRIMARY KEY(id)" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS element(" " id INTEGER, " " PRIMARY KEY(id)" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS element_component(" " id INTEGER, " " element_id INTEGER, " " type INTEGER, " " data TEXT, " " PRIMARY KEY(id), " " FOREIGN KEY(element_id) REFERENCES element(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS edge(" " id INTEGER NOT NULL, " " type INTEGER NOT NULL, " " source_node_id INTEGER NOT NULL, " " target_node_id INTEGER NOT NULL, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE, " " FOREIGN KEY(source_node_id) REFERENCES node(id) ON DELETE CASCADE, " " FOREIGN KEY(target_node_id) REFERENCES node(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS node(" " id INTEGER NOT NULL, " " type INTEGER NOT NULL, " " serialized_name TEXT, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS symbol(" " id INTEGER NOT NULL, " " definition_kind INTEGER NOT NULL, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS file(" " id INTEGER NOT NULL, " " path TEXT, " " language TEXT, " " modification_time TEXT, " " indexed INTEGER, " " complete INTEGER, " " line_count INTEGER, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS filecontent(" " id INTERGER, " " content TEXT, " " FOREIGN KEY(id) REFERENCES file(id)" " ON DELETE CASCADE " " ON UPDATE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS local_symbol(" " id INTEGER NOT NULL, " " name TEXT, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS source_location(" " id INTEGER NOT NULL, " " file_node_id INTEGER, " " start_line INTEGER, " " start_column INTEGER, " " end_line INTEGER, " " end_column INTEGER, " " type INTEGER, " " PRIMARY KEY(id), " " FOREIGN KEY(file_node_id) REFERENCES node(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS occurrence(" " element_id INTEGER NOT NULL, " " source_location_id INTEGER NOT NULL, " " PRIMARY KEY(element_id, source_location_id), " " FOREIGN KEY(element_id) REFERENCES element(id) ON DELETE CASCADE, " " FOREIGN KEY(source_location_id) REFERENCES source_location(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS component_access(" " node_id INTEGER NOT NULL, " " type INTEGER NOT NULL, " " PRIMARY KEY(node_id), " " FOREIGN KEY(node_id) REFERENCES node(id) ON DELETE CASCADE" ");"); executeStatement( "CREATE TABLE IF NOT EXISTS error(" " id INTEGER NOT NULL, " " message TEXT, " " fatal INTEGER NOT NULL, " " indexed INTEGER NOT NULL, " " translation_unit TEXT, " " PRIMARY KEY(id), " " FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE" ");"); } void DatabaseStorage::clearTables() { const std::vector tableNames = { "meta", "error", "component_access", "occurrence", "source_location", "local_symbol", "filecontent", "file", "symbol", "node", "edge", "element_component" "element"}; for (const std::string& tableName: tableNames) { executeStatement("DROP TABLE IF EXISTS main." + tableName + ";"); } } void DatabaseStorage::setupIndices() { executeStatement("CREATE INDEX IF NOT EXISTS node_serialized_name_index ON node(serialized_name);"); executeStatement("CREATE INDEX IF NOT EXISTS edge_source_target_type_index ON edge(source_node_id, target_node_id, type);"); executeStatement("CREATE INDEX IF NOT EXISTS local_symbol_name_index ON local_symbol(name);"); executeStatement( "CREATE INDEX IF NOT EXISTS source_location_all_data_index " "ON source_location(file_node_id, start_line, start_column, end_line, end_column, type);"); executeStatement("CREATE INDEX IF NOT EXISTS error_all_data_index ON error(message, fatal);"); } void DatabaseStorage::setupPrecompiledStatements() { m_insertElementStatement = compileStatement("INSERT INTO element(id) VALUES(NULL);"); m_insertElementComponentStatement = compileStatement( "INSERT INTO element_component(id, element_id, type, data) VALUES(NULL, ?, ?, ?);"); m_findNodeStatement = compileStatement("SELECT id FROM node WHERE serialized_name == ? LIMIT 1;"); m_insertNodeStatement = compileStatement("INSERT INTO node(id, type, serialized_name) VALUES(?, ?, ?);"); m_setNodeTypeStmt = compileStatement("UPDATE node SET type = ? WHERE id == ?;"); m_insertSymbolStatement = compileStatement("INSERT OR IGNORE INTO symbol(id, definition_kind) VALUES(?, ?);"); m_findFileStatement = compileStatement("SELECT id FROM file WHERE id == ?;"); m_insertFileStatement = compileStatement( "INSERT OR IGNORE INTO file(id, path, language, modification_time, indexed, complete, line_count) VALUES(?, ?, ?, ?, ?, ?, ?);"); m_setFileLanguageStmt = compileStatement("UPDATE file SET language = ? WHERE id == ?;"); m_insertFileContentStatement = compileStatement("INSERT INTO filecontent(id, content) VALUES(?, ?);"); m_findEdgeStatement = compileStatement("SELECT id FROM edge WHERE source_node_id == ? AND target_node_id == ? AND type == ? LIMIT 1;"); m_insertEdgeStatement = compileStatement("INSERT INTO edge(id, type, source_node_id, target_node_id) VALUES(?, ?, ?, ?);"); m_findLocalSymbolStmt = compileStatement("SELECT id FROM local_symbol WHERE name == ? LIMIT 1;"); m_insertLocalSymbolStmt = compileStatement("INSERT INTO local_symbol(id, name) VALUES(?, ?);"); m_findSourceLocationStmt = compileStatement( "SELECT id FROM source_location WHERE " "file_node_id = ? AND " "start_line = ? AND " "start_column = ? AND " "end_line = ? AND " "end_column = ? AND " "type = ? " "LIMIT 1;"); m_insertSourceLocationStmt = compileStatement( "INSERT INTO source_location(" "id, file_node_id, start_line, start_column, end_line, end_column, type) " "VALUES(NULL, ?, ?, ?, ?, ?, ?);"); m_insertOccurenceStmt = compileStatement("INSERT OR IGNORE INTO occurrence(element_id, source_location_id) VALUES(?, ?);"); m_findErrorStatement = compileStatement( "SELECT id FROM error WHERE " "message = ? AND " "fatal == ? " "LIMIT 1;"); m_insertErrorStatement = compileStatement( "INSERT INTO error(id, message, fatal, indexed, translation_unit) " "VALUES(?, ?, ?, ?, ?);"); m_insertOrUpdateMetaValueStmt = compileStatement( "INSERT OR REPLACE INTO meta(id, key, value) VALUES(" "(SELECT id FROM meta WHERE key = ?), ?, ?" ");"); } void DatabaseStorage::clearPrecompiledStatements() { m_insertElementStatement.finalize(); m_insertElementComponentStatement.finalize(); m_findNodeStatement.finalize(); m_insertNodeStatement.finalize(); m_setNodeTypeStmt.finalize(); m_insertSymbolStatement.finalize(); m_findFileStatement.finalize(); m_insertFileStatement.finalize(); m_setFileLanguageStmt.finalize(); m_insertFileContentStatement.finalize(); m_findEdgeStatement.finalize(); m_insertEdgeStatement.finalize(); m_findLocalSymbolStmt.finalize(); m_insertLocalSymbolStmt.finalize(); m_findSourceLocationStmt.finalize(); m_insertSourceLocationStmt.finalize(); m_insertOccurenceStmt.finalize(); m_findErrorStatement.finalize(); m_insertErrorStatement.finalize(); m_insertOrUpdateMetaValueStmt.finalize(); } int DatabaseStorage::insertElement() { executeStatement(m_insertElementStatement); const int id = static_cast(m_database.lastRowId()); m_insertElementStatement.reset(); return id; } void DatabaseStorage::insertOrUpdateMetaValue(const std::string& key, const std::string& value) { m_insertOrUpdateMetaValueStmt.bind(1, key.c_str()); m_insertOrUpdateMetaValueStmt.bind(2, key.c_str()); m_insertOrUpdateMetaValueStmt.bind(3, value.c_str()); executeStatement(m_insertOrUpdateMetaValueStmt); m_insertOrUpdateMetaValueStmt.reset(); } CppSQLite3Statement DatabaseStorage::compileStatement(const std::string& statement) const { try { return m_database.compileStatement(statement.c_str()); } catch (CppSQLite3Exception e) { throw SourcetrailException("Failed to compile statement \"" + statement + "\" with message \"" + e.errorMessage() + "\"."); } return CppSQLite3Statement(); } void DatabaseStorage::executeStatement(const std::string& statement) const { try { m_database.execDML(statement.c_str()); } catch (CppSQLite3Exception e) { throw SourcetrailException("Failed to execute statement \"" + statement + "\" with message \"" + e.errorMessage() + "\"."); } } void DatabaseStorage::executeStatement(CppSQLite3Statement& statement) const { try { statement.execDML(); } catch (CppSQLite3Exception e) { throw SourcetrailException("Failed to execute statement with message \"" + std::string(e.errorMessage()) + "\"."); } } CppSQLite3Query DatabaseStorage::executeQuery(const std::string& query) const { try { return m_database.execQuery(query.c_str()); } catch (CppSQLite3Exception e) { throw SourcetrailException("Failed to execute query \"" + query + "\" with message \"" + e.errorMessage() + "\"."); } } CppSQLite3Query DatabaseStorage::executeQuery(CppSQLite3Statement& statement) const { try { return statement.execQuery(); } catch (CppSQLite3Exception e) { throw SourcetrailException("Failed to execute query with message \"" + std::string(e.errorMessage()) + "\"."); } } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, type, source_node_id, target_node_id FROM edge " + query + ";"); std::vector edges; while (!q.eof()) { const int id = q.getIntField(0, 0); const int edgeKind = q.getIntField(1, -1); const int sourceId = q.getIntField(2, 0); const int targetId = q.getIntField(3, 0); if (id != 0 && edgeKind != -1) { edges.emplace_back(StorageEdge(id, sourceId, targetId, edgeKind)); } q.nextRow(); } return edges; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, type, serialized_name FROM node " + query + ";"); std::vector nodes; while (!q.eof()) { const int id = q.getIntField(0, 0); const int type = q.getIntField(1, -1); const std::string serializedName = q.getStringField(2, ""); if (id != 0 && type != -1) { nodes.emplace_back(StorageNode(id, type, serializedName)); } q.nextRow(); } return nodes; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, definition_kind FROM symbol " + query + ";"); std::vector symbols; while (!q.eof()) { const int id = q.getIntField(0, 0); const int definitionKind = q.getIntField(1, 0); if (id != 0) { symbols.emplace_back(StorageSymbol(id, definitionKind)); } q.nextRow(); } return symbols; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, path, language, modification_time, indexed, complete FROM file " + query + ";"); std::vector files; while (!q.eof()) { const int id = q.getIntField(0, 0); const std::string filePath = q.getStringField(1, ""); const std::string languageIdentifier = q.getStringField(2, ""); const std::string modificationTime = q.getStringField(3, ""); const bool indexed = q.getIntField(4, 0); const bool complete = q.getIntField(5, 0); if (id != 0) { files.emplace_back(StorageFile(id, filePath, languageIdentifier, modificationTime, indexed, complete)); } q.nextRow(); } return files; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, name FROM local_symbol " + query + ";"); std::vector localSymbols; while (!q.eof()) { const int id = q.getIntField(0, 0); const std::string name = q.getStringField(1, ""); if (id != 0) { localSymbols.emplace_back(StorageLocalSymbol(id, name)); } q.nextRow(); } return localSymbols; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery( "SELECT id, file_node_id, start_line, start_column, end_line, end_column, type FROM source_location " + query + ";"); std::vector sourceLocations; while (!q.eof()) { const int id = q.getIntField(0, 0); const int fileNodeId = q.getIntField(1, 0); const int startLineNumber = q.getIntField(2, -1); const int startColNumber = q.getIntField(3, -1); const int endLineNumber = q.getIntField(4, -1); const int endColNumber = q.getIntField(5, -1); const int locationKind = q.getIntField(6, -1); if (id != 0 && fileNodeId != 0 && startLineNumber != -1 && startColNumber != -1 && endLineNumber != -1 && endColNumber != -1 && locationKind != -1) { sourceLocations.emplace_back( StorageSourceLocation(id, fileNodeId, startLineNumber, startColNumber, endLineNumber, endColNumber, locationKind)); } q.nextRow(); } return sourceLocations; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT element_id, source_location_id FROM occurrence " + query + ";"); std::vector occurrences; while (!q.eof()) { const int elementId = q.getIntField(0, 0); const int sourceLocationId = q.getIntField(1, 0); if (elementId != 0 && sourceLocationId != 0) { occurrences.emplace_back(StorageOccurrence(elementId, sourceLocationId)); } q.nextRow(); } return occurrences; } template <> std::vector DatabaseStorage::doGetAll(const std::string& query) const { CppSQLite3Query q = executeQuery("SELECT id, message, fatal, indexed, translation_unit FROM error " + query + ";"); std::vector errors; while (!q.eof()) { const int id = q.getIntField(0, 0); const std::string message = q.getStringField(1, ""); const bool fatal = q.getIntField(2, 0); const bool indexed = q.getIntField(3, 0); const std::string translationUnit = q.getStringField(4, ""); if (id != 0) { errors.emplace_back(StorageError(id, message, translationUnit, fatal, indexed)); } q.nextRow(); } return errors; } } // namespace sourcetrail