summaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/viewmodifier.cpp
blob: 36ab4579b41de6cdbc6b48cd8484327cb5886485 (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
#include "viewmodifier.h"
#include "common/utils_sql.h"
#include "parser/parser.h"
#include "schemaresolver.h"
#include "selectresolver.h"
#include "parser/ast/sqlitecreatetrigger.h"
#include "common/unused.h"

ViewModifier::ViewModifier(Db* db, const QString& view) :
    ViewModifier(db, "main", view)
{
}

ViewModifier::ViewModifier(Db* db, const QString& database, const QString& view) :
    db(db), database(database), view(view)
{
    dialect = db->getDialect();
}

void ViewModifier::alterView(const QString& newView)
{
    Parser parser(dialect);
    if (!parser.parse(newView) || parser.getQueries().size() == 0)
    {
        errors << QObject::tr("Could not parse DDL of the view to be created. Details: %1").arg(parser.getErrorString());
        return;
    }

    SqliteQueryPtr query = parser.getQueries().first();
    createView = query.dynamicCast<SqliteCreateView>();

    if (!createView)
    {
        errors << QObject::tr("Parsed query is not CREATE VIEW. It's: %1").arg(sqliteQueryTypeToString(query->queryType));
        return;
    }

    alterView(createView);
}

void ViewModifier::alterView(SqliteCreateViewPtr newView)
{
    createView = newView;

    addMandatorySql(QString("DROP VIEW %1").arg(wrapObjIfNeeded(view, dialect)));
    addMandatorySql(newView->detokenize());

    collectNewColumns();
    handleTriggers();

    // TODO handle other views selecting from this view
}

void ViewModifier::handleTriggers()
{
    SchemaResolver resolver(db);
    QList<SqliteCreateTriggerPtr> triggers = resolver.getParsedTriggersForView(view, true);
    foreach (SqliteCreateTriggerPtr trigger, triggers)
    {
        addOptionalSql(QString("DROP TRIGGER %1").arg(wrapObjIfNeeded(trigger->trigger, dialect)));

        if (!handleNewColumns(trigger))
            continue;

        addOptionalSql(trigger->detokenize());
    }
}

bool ViewModifier::handleNewColumns(SqliteCreateTriggerPtr trigger)
{
    UNUSED(trigger);
    // TODO update all occurances of columns in "UPDATE OF" and statements inside, just like it would be done in TableModifier.
    return true;
}

void ViewModifier::collectNewColumns()
{
    SelectResolver resolver(db, createView->select->detokenize());
    QList<QList<SelectResolver::Column> > multiColumns = resolver.resolve(createView->select);
    if (multiColumns.size() < 1)
    {
        warnings << QObject::tr("SQLiteStudio was unable to resolve columns returned by the new view, "
                                "therefore it won't be able to tell which triggers might fail during the recreation process.");
        return;
    }

    foreach (const SelectResolver::Column& col, multiColumns.first())
        newColumns << col.column;
}

void ViewModifier::addMandatorySql(const QString& sql)
{
    sqls << sql;
    sqlMandatoryFlags << true;
}

void ViewModifier::addOptionalSql(const QString& sql)
{

    sqls << sql;
    sqlMandatoryFlags << false;
}

QStringList ViewModifier::generateSqls() const
{
    return sqls;
}

QList<bool> ViewModifier::getMandatoryFlags() const
{
    return sqlMandatoryFlags;
}

QStringList ViewModifier::getWarnings() const
{
    return warnings;
}

QStringList ViewModifier::getErrors() const
{
    return errors;
}

bool ViewModifier::hasMessages() const
{
    return errors.size() > 0 || warnings.size() > 0;
}