2017-08-21 12:00:27 +02:00
/****************************************************************************
* *
* * Copyright ( C ) 2017 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
* *
* * This file is part of Qt Creator .
* *
* * Commercial License Usage
* * Licensees holding valid commercial Qt licenses may use this file in
* * accordance with the commercial license agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and The Qt Company . For licensing terms
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
* *
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3 as published by the Free Software
* * Foundation with exceptions as appearing in the file LICENSE . GPL3 - EXCEPT
* * included in the packaging of this file . Please review the following
* * information to ensure the GNU General Public License requirements will
* * be met : https : //www.gnu.org/licenses/gpl-3.0.html.
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# pragma once
# include "symbolstorageinterface.h"
2018-10-11 18:09:55 +02:00
# include <filepathcachingfwd.h>
2017-08-17 12:44:52 +02:00
# include <sqliteexception.h>
2017-08-21 12:00:27 +02:00
# include <sqlitetransaction.h>
2018-10-11 18:09:55 +02:00
# include <sqlitetable.h>
2017-08-17 12:44:52 +02:00
2018-01-22 14:21:01 +01:00
# include <QJsonArray>
2018-02-06 19:03:14 +01:00
# include <QJsonDocument>
# include <QJsonObject>
2018-01-22 14:21:01 +01:00
2017-08-21 12:00:27 +02:00
namespace ClangBackEnd {
2018-10-11 18:09:55 +02:00
template < typename DatabaseType >
2018-01-22 14:21:01 +01:00
class SymbolStorage final : public SymbolStorageInterface
2017-08-21 12:00:27 +02:00
{
2018-10-11 18:09:55 +02:00
using Database = DatabaseType ;
using ReadStatement = typename Database : : ReadStatement ;
using WriteStatement = typename Database : : WriteStatement ;
2017-08-21 12:00:27 +02:00
public :
2018-10-11 18:09:55 +02:00
SymbolStorage ( Database & database )
: m_transaction ( database ) ,
m_database ( database )
2017-08-21 12:00:27 +02:00
{
2018-10-11 18:09:55 +02:00
m_transaction . commit ( ) ;
2017-08-21 12:00:27 +02:00
}
void addSymbolsAndSourceLocations ( const SymbolEntries & symbolEntries ,
const SourceLocationEntries & sourceLocations ) override
{
fillTemporarySymbolsTable ( symbolEntries ) ;
fillTemporaryLocationsTable ( sourceLocations ) ;
addNewSymbolsToSymbols ( ) ;
syncNewSymbolsFromSymbols ( ) ;
syncSymbolsIntoNewLocations ( ) ;
deleteAllLocationsFromUpdatedFiles ( ) ;
insertNewLocationsInLocations ( ) ;
deleteNewSymbolsTable ( ) ;
deleteNewLocationsTable ( ) ;
2018-01-22 14:21:01 +01:00
}
2018-08-28 12:08:37 +02:00
int insertOrUpdateProjectPart ( Utils : : SmallStringView projectPartName ,
2018-01-29 12:07:15 +01:00
const Utils : : SmallStringVector & commandLineArguments ,
2018-02-08 12:48:46 +01:00
const CompilerMacros & compilerMacros ,
const Utils : : SmallStringVector & includeSearchPaths ) override
2018-01-22 14:21:01 +01:00
{
2018-10-11 18:09:55 +02:00
m_database . setLastInsertedRowId ( - 1 ) ;
2018-01-22 14:21:01 +01:00
Utils : : SmallString compilerArguementsAsJson = toJson ( commandLineArguments ) ;
2018-02-06 19:03:14 +01:00
Utils : : SmallString compilerMacrosAsJson = toJson ( compilerMacros ) ;
2018-02-08 12:48:46 +01:00
Utils : : SmallString includeSearchPathsAsJason = toJson ( includeSearchPaths ) ;
2018-01-22 14:21:01 +01:00
2018-10-11 18:09:55 +02:00
WriteStatement & insertStatement = m_insertProjectPartStatement ;
2018-02-08 12:48:46 +01:00
insertStatement . write ( projectPartName ,
compilerArguementsAsJson ,
compilerMacrosAsJson ,
includeSearchPathsAsJason ) ;
2018-01-22 14:21:01 +01:00
2018-10-11 18:09:55 +02:00
if ( m_database . lastInsertedRowId ( ) = = - 1 ) {
WriteStatement & updateStatement = m_updateProjectPartStatement ;
2018-02-08 12:48:46 +01:00
updateStatement . write ( compilerArguementsAsJson ,
compilerMacrosAsJson ,
2018-02-20 12:43:05 +01:00
includeSearchPathsAsJason ,
projectPartName ) ;
2018-01-22 14:21:01 +01:00
}
2018-08-28 12:08:37 +02:00
2018-10-11 18:09:55 +02:00
return int ( m_database . lastInsertedRowId ( ) ) ;
2018-01-22 14:21:01 +01:00
}
2018-02-06 11:16:29 +01:00
Utils : : optional < ProjectPartArtefact > fetchProjectPartArtefact ( FilePathId sourceId ) const override
{
2018-10-11 18:09:55 +02:00
ReadStatement & statement = m_getProjectPartArtefactsBySourceId ;
2018-02-06 11:16:29 +01:00
2018-02-08 12:48:46 +01:00
return statement . template value < ProjectPartArtefact , 4 > ( sourceId . filePathId ) ;
2018-02-06 11:16:29 +01:00
}
2018-02-07 16:18:16 +01:00
Utils : : optional < ProjectPartArtefact > fetchProjectPartArtefact ( Utils : : SmallStringView projectPartName ) const override
{
2018-10-11 18:09:55 +02:00
ReadStatement & statement = m_getProjectPartArtefactsByProjectPartName ;
2018-02-07 16:18:16 +01:00
2018-02-08 12:48:46 +01:00
return statement . template value < ProjectPartArtefact , 4 > ( projectPartName ) ;
2018-02-07 16:18:16 +01:00
}
2018-02-06 11:16:29 +01:00
void updateProjectPartSources ( int projectPartId ,
const FilePathIds & sourceFilePathIds ) override
{
2018-10-11 18:09:55 +02:00
WriteStatement & deleteStatement = m_deleteAllProjectPartsSourcesWithProjectPartIdStatement ;
2018-01-22 14:21:01 +01:00
deleteStatement . write ( projectPartId ) ;
2018-10-11 18:09:55 +02:00
WriteStatement & insertStatement = m_insertProjectPartSourcesStatement ;
2018-01-22 14:21:01 +01:00
for ( const FilePathId & sourceFilePathId : sourceFilePathIds )
insertStatement . write ( projectPartId , sourceFilePathId . filePathId ) ;
}
static Utils : : SmallString toJson ( const Utils : : SmallStringVector & strings )
{
QJsonDocument document ;
QJsonArray array ;
std : : transform ( strings . begin ( ) , strings . end ( ) , std : : back_inserter ( array ) , [ ] ( const auto & string ) {
return QJsonValue ( string . data ( ) ) ;
} ) ;
document . setArray ( array ) ;
2017-08-21 12:00:27 +02:00
2018-02-06 19:03:14 +01:00
return document . toJson ( QJsonDocument : : Compact ) ;
}
static Utils : : SmallString toJson ( const CompilerMacros & compilerMacros )
{
QJsonDocument document ;
QJsonObject object ;
for ( const CompilerMacro & macro : compilerMacros )
object . insert ( QString ( macro . key ) , QString ( macro . value ) ) ;
document . setObject ( object ) ;
2018-01-22 14:21:01 +01:00
return document . toJson ( QJsonDocument : : Compact ) ;
2017-08-21 12:00:27 +02:00
}
void fillTemporarySymbolsTable ( const SymbolEntries & symbolEntries )
{
2018-10-11 18:09:55 +02:00
WriteStatement & statement = m_insertSymbolsToNewSymbolsStatement ;
2017-08-21 12:00:27 +02:00
for ( const auto & symbolEntry : symbolEntries ) {
statement . write ( symbolEntry . first ,
symbolEntry . second . usr ,
2018-04-05 10:58:33 +02:00
symbolEntry . second . symbolName ,
static_cast < uint > ( symbolEntry . second . symbolKind ) ) ;
2017-08-21 12:00:27 +02:00
}
}
void fillTemporaryLocationsTable ( const SourceLocationEntries & sourceLocations )
{
2018-10-11 18:09:55 +02:00
WriteStatement & statement = m_insertLocationsToNewLocationsStatement ;
2017-08-21 12:00:27 +02:00
2018-04-09 13:30:30 +02:00
for ( const auto & locationEntry : sourceLocations ) {
statement . write ( locationEntry . symbolId ,
locationEntry . lineColumn . line ,
locationEntry . lineColumn . column ,
locationEntry . filePathId . filePathId ,
int ( locationEntry . kind ) ) ;
2017-08-21 12:00:27 +02:00
}
}
void addNewSymbolsToSymbols ( )
{
2018-10-11 18:09:55 +02:00
m_addNewSymbolsToSymbolsStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void syncNewSymbolsFromSymbols ( )
{
2018-10-11 18:09:55 +02:00
m_syncNewSymbolsFromSymbolsStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void syncSymbolsIntoNewLocations ( )
{
2018-10-11 18:09:55 +02:00
m_syncSymbolsIntoNewLocationsStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void deleteAllLocationsFromUpdatedFiles ( )
{
2018-10-11 18:09:55 +02:00
m_deleteAllLocationsFromUpdatedFilesStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void insertNewLocationsInLocations ( )
{
2018-10-11 18:09:55 +02:00
m_insertNewLocationsInLocationsStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void deleteNewSymbolsTable ( )
{
2018-10-11 18:09:55 +02:00
m_deleteNewSymbolsTableStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
void deleteNewLocationsTable ( )
{
2018-10-11 18:09:55 +02:00
m_deleteNewLocationsTableStatement . execute ( ) ;
2017-08-21 12:00:27 +02:00
}
2018-02-20 12:43:05 +01:00
Utils : : optional < ProjectPartPch > fetchPrecompiledHeader ( int projectPartId ) const
{
2018-10-11 18:09:55 +02:00
return m_getPrecompiledHeader . template value < ProjectPartPch , 2 > ( projectPartId ) ;
2018-02-20 12:43:05 +01:00
}
2017-08-21 12:00:27 +02:00
SourceLocationEntries sourceLocations ( ) const
{
return SourceLocationEntries ( ) ;
}
2018-10-11 18:09:55 +02:00
Sqlite : : Table createNewSymbolsTable ( ) const
{
Sqlite : : Table table ;
table . setName ( " newSymbols " ) ;
table . setUseTemporaryTable ( true ) ;
table . addColumn ( " temporarySymbolId " , Sqlite : : ColumnType : : Integer , Sqlite : : Contraint : : PrimaryKey ) ;
const Sqlite : : Column & symbolIdColumn = table . addColumn ( " symbolId " , Sqlite : : ColumnType : : Integer ) ;
const Sqlite : : Column & usrColumn = table . addColumn ( " usr " , Sqlite : : ColumnType : : Text ) ;
const Sqlite : : Column & symbolNameColumn = table . addColumn ( " symbolName " , Sqlite : : ColumnType : : Text ) ;
table . addColumn ( " symbolKind " , Sqlite : : ColumnType : : Integer ) ;
table . addIndex ( { usrColumn , symbolNameColumn } ) ;
table . addIndex ( { symbolIdColumn } ) ;
table . initialize ( m_database ) ;
return table ;
}
Sqlite : : Table createNewLocationsTable ( ) const
{
Sqlite : : Table table ;
table . setName ( " newLocations " ) ;
table . setUseTemporaryTable ( true ) ;
table . addColumn ( " temporarySymbolId " , Sqlite : : ColumnType : : Integer ) ;
table . addColumn ( " symbolId " , Sqlite : : ColumnType : : Integer ) ;
const Sqlite : : Column & sourceIdColumn = table . addColumn ( " sourceId " , Sqlite : : ColumnType : : Integer ) ;
const Sqlite : : Column & lineColumn = table . addColumn ( " line " , Sqlite : : ColumnType : : Integer ) ;
const Sqlite : : Column & columnColumn = table . addColumn ( " column " , Sqlite : : ColumnType : : Integer ) ;
table . addColumn ( " locationKind " , Sqlite : : ColumnType : : Integer ) ;
table . addUniqueIndex ( { sourceIdColumn , lineColumn , columnColumn } ) ;
table . initialize ( m_database ) ;
return table ;
}
public :
Sqlite : : ImmediateNonThrowingDestructorTransaction m_transaction ;
Database & m_database ;
Sqlite : : Table newSymbolsTablet { createNewSymbolsTable ( ) } ;
Sqlite : : Table newLocationsTable { createNewLocationsTable ( ) } ;
WriteStatement m_insertSymbolsToNewSymbolsStatement {
" INSERT INTO newSymbols(temporarySymbolId, usr, symbolName, symbolKind) VALUES(?,?,?,?) " ,
m_database } ;
WriteStatement m_insertLocationsToNewLocationsStatement {
" INSERT OR IGNORE INTO newLocations(temporarySymbolId, line, column, sourceId, locationKind) VALUES(?,?,?,?,?) " ,
m_database
} ;
ReadStatement m_selectNewSourceIdsStatement {
" SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources WHERE newLocations.sourceId == sources.sourceId) " ,
m_database
} ;
WriteStatement m_addNewSymbolsToSymbolsStatement {
" INSERT INTO symbols(usr, symbolName, symbolKind) "
" SELECT usr, symbolName, symbolKind FROM newSymbols WHERE NOT EXISTS "
" (SELECT usr FROM symbols WHERE symbols.usr == newSymbols.usr) " ,
m_database
} ;
WriteStatement m_syncNewSymbolsFromSymbolsStatement {
" UPDATE newSymbols SET symbolId = (SELECT symbolId FROM symbols WHERE newSymbols.usr = symbols.usr) " ,
m_database
} ;
WriteStatement m_syncSymbolsIntoNewLocationsStatement {
" UPDATE newLocations SET symbolId = (SELECT symbolId FROM newSymbols WHERE newSymbols.temporarySymbolId = newLocations.temporarySymbolId) " ,
m_database
} ;
WriteStatement m_deleteAllLocationsFromUpdatedFilesStatement {
" DELETE FROM locations WHERE sourceId IN (SELECT DISTINCT sourceId FROM newLocations) " ,
m_database
} ;
WriteStatement m_insertNewLocationsInLocationsStatement {
" INSERT INTO locations(symbolId, line, column, sourceId, locationKind) SELECT symbolId, line, column, sourceId, locationKind FROM newLocations " ,
m_database
} ;
WriteStatement m_deleteNewSymbolsTableStatement {
" DELETE FROM newSymbols " ,
m_database
} ;
WriteStatement m_deleteNewLocationsTableStatement {
" DELETE FROM newLocations " ,
m_database
} ;
WriteStatement m_insertProjectPartStatement {
" INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments, compilerMacros, includeSearchPaths) VALUES (?,?,?,?) " ,
m_database
} ;
WriteStatement m_updateProjectPartStatement {
" UPDATE projectParts SET compilerArguments = ?, compilerMacros = ?, includeSearchPaths = ? WHERE projectPartName = ? " ,
m_database
} ;
mutable ReadStatement m_getProjectPartIdStatement {
" SELECT projectPartId FROM projectParts WHERE projectPartName = ? " ,
m_database
} ;
WriteStatement m_deleteAllProjectPartsSourcesWithProjectPartIdStatement {
" DELETE FROM projectPartsSources WHERE projectPartId = ? " ,
m_database
} ;
WriteStatement m_insertProjectPartSourcesStatement {
" INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?) " ,
m_database
} ;
mutable ReadStatement m_getCompileArgumentsForFileIdStatement {
" SELECT compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?) " ,
m_database
} ;
mutable ReadStatement m_getProjectPartArtefactsBySourceId {
" SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?) " ,
m_database
} ;
mutable ReadStatement m_getProjectPartArtefactsByProjectPartName {
" SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ? " ,
m_database
} ;
mutable ReadStatement m_getPrecompiledHeader {
" SELECT pchPath, pchBuildTime FROM precompiledHeaders WHERE projectPartId = ? " ,
m_database
} ;
2017-08-21 12:00:27 +02:00
} ;
} // namespace ClangBackEnd