aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/dbobjectorganizer.h
blob: c8a1f9791068ebc08f7d034386821fd87c9fac1d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef DBOBJECTORGANIZER_H
#define DBOBJECTORGANIZER_H

#include "coreSQLiteStudio_global.h"
#include "interruptable.h"
#include "schemaresolver.h"
#include <QString>
#include <QObject>
#include <QRunnable>
#include <QMutex>
#include <QStringList>
#include <QHash>

class Db;

class API_EXPORT DbObjectOrganizer : public QObject, public QRunnable, public Interruptable
{
        Q_OBJECT

    public:
        typedef std::function<bool(const QStringList& tables)> ReferencedTablesConfimFunction;
        typedef std::function<bool(QString& nameInConflict)> NameConflictResolveFunction;
        typedef std::function<bool(const QList<QPair<QString,QString>>& diffs)> ConversionConfimFunction;
        typedef std::function<bool(const QHash<QString,QSet<QString>>& errors)> ConversionErrorsConfimFunction;

        /**
         * @brief Creates organizer with default handler functions.
         *
         * The default handler functions are not very usable - they always return false.
         * It's better to use the other constructor and pass the custom implementation of
         * handler functions.
         */
        DbObjectOrganizer();

        /**
         * @brief Creates organizer with handler functions defined specially for it.
         * @param confirmFunction Implemented function should ask user if he wants to include referenced tables
         * in the copy/move action. If it returns false, then referenced tables will be excluded.
         * @param nameConflictResolveFunction Implemented function should ask user for a new name for the object
         * with the name passed in the argument. The new name should be returned in the very same reference argument.
         * If the function returns false, then the conflict is unresolved and copy/move action will be aborted.
         * When the function returns true, it means that the user entered a new name and he wants to proceed.
         * @param conversionConfimFunction This function should display changes that will be made to the SQL statements
         * while executing them on the target database (because of different database versions). User can cancel the process
         * (in which case, the function should return false).
         * @param conversionErrorsConfimFunction This function should display critical errors that occurred when tried to
         * convert SQL statements for target database. User
         * can choose to proceed (with skipping problemating database objects), or cancel the process (in which case the function
         * should return false).
         *
         * Use this constructor always if possible.
         */
        DbObjectOrganizer(ReferencedTablesConfimFunction confirmFunction,
                          NameConflictResolveFunction nameConflictResolveFunction,
                          ConversionConfimFunction conversionConfimFunction,
                          ConversionErrorsConfimFunction conversionErrorsConfimFunction);
        ~DbObjectOrganizer();

        void copyObjectsToDb(Db* srcDb, const QStringList& objNames, Db* dstDb, bool includeData, bool includeIndexes, bool includeTriggers);
        void moveObjectsToDb(Db* srcDb, const QStringList& objNames, Db* dstDb, bool includeData, bool includeIndexes, bool includeTriggers);
        void interrupt();
        bool isExecuting();
        void run();

    private:
        enum class Mode
        {
            PREPARE_TO_COPY_OBJECTS,
            PREPARE_TO_MOVE_OBJECTS,
            COPY_OBJECTS,
            MOVE_OBJECTS,
            unknown
        };

        void init();
        void reset();
        void copyOrMoveObjectsToDb(Db* srcDb, const QSet<QString>& objNames, Db* dstDb, bool includeData, bool includeIndexes, bool includeTriggers, bool move);
        void processPreparation();
        bool processAll();
        bool processDbObjects();
        bool processColumns();
        bool resolveNameConflicts();
        bool copyTableToDb(const QString& table);
        bool copyViewToDb(const QString& view);
        bool copyIndexToDb(const QString& index);
        bool copyTriggerToDb(const QString& trigger);
        bool copySimpleObjectToDb(const QString& name, const QString& errorMessage);
        QSet<QString> resolveReferencedTables(const QString& table, const QList<SqliteCreateTablePtr>& parsedTables);
        void collectReferencedTables(const QString& table, const StrHash<SqliteQueryPtr>& allParsedObjects);
        void collectReferencedIndexes(const QString& table);
        void collectReferencedTriggersForTable(const QString& table);
        void collectReferencedTriggersForView(const QString& view);
        void findBinaryColumns(const QString& table, const StrHash<SqliteQueryPtr>& allParsedObjects);
        bool copyDataAsMiddleware(const QString& table);
        bool copyDataUsingAttach(const QString& table);
        void dropTable(const QString& table);
        void dropView(const QString& view);
        void dropObject(const QString& name, const QString& type);
        bool setFkEnabled(bool enabled);
        bool isInterrupted();
        void setExecuting(bool executing);
        void setSrcAndDstDb(Db* srcDb, Db* dstDb);
        bool begin();
        bool commit();
        bool rollback();
        void emitFinished(bool success);
        bool execConfirmFunctionInMainThread(const QStringList& tables);
        QString prefixSimpleObjectWithAttachName(const QString& objName, const QString& ddl);

        ReferencedTablesConfimFunction confirmFunction;
        NameConflictResolveFunction nameConflictResolveFunction;
        ConversionConfimFunction conversionConfimFunction;
        ConversionErrorsConfimFunction conversionErrorsConfimFunction;
        Mode mode = Mode::COPY_OBJECTS;
        Db* srcDb = nullptr;
        Db* dstDb = nullptr;
        QSet<QString> srcNames;
        QSet<QString> srcTables;
        QSet<QString> srcViews;
        QSet<QString> srcIndexes;
        QSet<QString> srcTriggers;
        QHash<QString,QString> renamed;
        QString srcTable;
        QHash<QString,QStringList> binaryColumns;
        bool includeData = false;
        bool includeIndexes = false;
        bool includeTriggers = false;
        bool deleteSourceObjects = false;
        QSet<QString> referencedTables;
        QHash<QString,QSet<QString>> errorsToConfirm;
        QList<QPair<QString, QString>> diffListToConfirm;
        SchemaResolver* srcResolver = nullptr;
        SchemaResolver* dstResolver = nullptr;
        bool interrupted = false;
        bool executing = false;
        QMutex interruptMutex;
        QMutex executingMutex;
        QString attachName;

    private slots:
        void processPreparationFinished();
        bool confirmFunctionSlot(const QStringList& tables);

    signals:
        void finishedDbObjectsMove(bool success, Db* srcDb, Db* dstDb);
        void finishedDbObjectsCopy(bool success, Db* srcDb, Db* dstDb);
        void preparetionFinished();
};

#endif // DBOBJECTORGANIZER_H