#ifndef DBVERSIONCONVERTER_H #define DBVERSIONCONVERTER_H #include "parser/ast/sqlitequery.h" #include "parser/ast/sqliteorderby.h" #include #include #include #include class Db; class SchemaResolver; class SqliteCreateTable; class SqliteCreateTrigger; class SqliteCreateIndex; class SqliteCreateView; class SqliteCreateVirtualTable; class SqliteIndexedColumn; class SqliteSelect; class SqliteDelete; class SqliteUpdate; class SqliteInsert; class SqliteExpr; class SqliteBeginTrans; class API_EXPORT DbVersionConverter : public QObject { Q_OBJECT public: typedef std::function>& diffs)> ConversionConfimFunction; typedef std::function& errors)> ConversionErrorsConfimFunction; DbVersionConverter(); virtual ~DbVersionConverter(); void convert(Dialect from, Dialect to, Db* srcDb, const QString& targetFile, const QString& targetName, ConversionConfimFunction confirmFunc, ConversionErrorsConfimFunction errorsConfirmFunc); void convert(Dialect from, Dialect to, Db* db); void convert3To2(Db* db); void convert2To3(Db* db); QString convert(Dialect from, Dialect to, const QString& sql); QString convert3To2(const QString& sql); QString convert2To3(const QString& sql); SqliteQueryPtr convert(Dialect from, Dialect to, SqliteQueryPtr query); SqliteQueryPtr convert3To2(SqliteQueryPtr query); SqliteQueryPtr convert2To3(SqliteQueryPtr query); const QList >& getDiffList() const; const QSet& getErrors() const; const QList& getConverted() const; QStringList getConvertedSqls() const; void reset(); QList getSupportedVersions() const; QStringList getSupportedVersionNames() const; private: struct FullConversionConfig { Dialect from; Dialect to; Db* srcDb = nullptr; QString targetFile; QString targetName; ConversionConfimFunction confirmFunc = nullptr; ConversionErrorsConfimFunction errorsConfirmFunc = nullptr; }; void fullConvertStep1(); void fullConvertStep2(); bool fullConvertCreateObjectsStep1(Db* db, QStringList& tables); bool fullConvertCreateObjectsStep2(Db* db); bool fullConvertCopyData(Db* db, const QStringList& tables); bool checkForInterrupted(Db* db, bool rollback); void convertDb(); QList parse(const QString& sql, Dialect dialect); bool modifySelectForVersion2(SqliteSelect* select); bool modifyDeleteForVersion2(SqliteDelete* del); bool modifyInsertForVersion2(SqliteInsert* insert); bool modifyUpdateForVersion2(SqliteUpdate* update); bool modifyCreateTableForVersion2(SqliteCreateTable* createTable); bool modifyCreateTriggerForVersion2(SqliteCreateTrigger* createTrigger); bool modifyCreateIndexForVersion2(SqliteCreateIndex* createIndex); bool modifyCreateViewForVersion2(SqliteCreateView* createView); bool modifyVirtualTableForVesion2(SqliteQueryPtr& query, SqliteCreateVirtualTable* createVirtualTable); bool modifyAllExprsForVersion2(SqliteStatement* stmt); bool modifySingleExprForVersion2(SqliteExpr* expr); bool modifyAllIndexedColumnsForVersion2(SqliteStatement* stmt); bool modifySingleIndexedColumnForVersion2(SqliteExtendedIndexedColumn* idxCol); bool modifyBeginTransForVersion3(SqliteBeginTrans* begin); bool modifyCreateTableForVersion3(SqliteCreateTable* createTable); QString getSqlForDiff(SqliteStatement* stmt); void storeDiff(const QString& sql1, SqliteStatement* stmt); void storeErrorDiff(SqliteStatement* stmt); QList getAllPossibleDbInstances() const; QString generateQueryPlaceholders(int argCount); void sortConverted(); void setInterrupted(bool value); bool isInterrupted(); void conversionInterrupted(Db* db, bool rollback); template bool modifyAllIndexedColumnsForVersion2(const QList columns) { for (T* idxCol : columns) { if (!modifySingleIndexedColumnForVersion2(idxCol)) return false; } return true; } template QSharedPointer copyQuery(SqliteQueryPtr query) { return QSharedPointer::create(*(query.dynamicCast().data())); } Db* db = nullptr; Dialect targetDialect = Dialect::Sqlite3; SchemaResolver* resolver = nullptr; QList> diffList; QSet errors; QList newQueries; FullConversionConfig* fullConversionConfig = nullptr; bool interrupted = false; QMutex interruptMutex; /** * @brief Whether to include non-DDL statements in diff list. * * The non-DDL statements are INSERTs, SELECTs, etc. * Normally, for DB conversion we only care about DDL modifications, * that is for CREATE statements. Other statements may appear inside of * triggers or views, but we don't need their diffs separately. * * This variable is not used currently, but may be in future, * when for example individual INSERT statement would need to be converted. * Right now there's no such need, but it would be pity to remove the code * from that non-DDL statements. */ bool diffsForNonDDL = false; private slots: void conversionError(Db* db, const QString& errMsg); void confirmConversion(); void registerDbAfterSuccessfulConversion(); public slots: void interrupt(); signals: void askUserForConfirmation(); void conversionSuccessful(); void conversionAborted(); void conversionFailed(const QString& errorMsg); }; #endif // DBVERSIONCONVERTER_H