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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#ifndef TABLEMODIFIER_H
#define TABLEMODIFIER_H
#include "db/db.h"
#include "selectresolver.h"
#include "parser/ast/sqlitecreatetable.h"
#include "parser/ast/sqliteupdate.h"
#include "parser/ast/sqliteinsert.h"
#include "parser/ast/sqlitedelete.h"
#include "parser/ast/sqlitecreateindex.h"
#include "parser/ast/sqlitecreatetrigger.h"
#include "parser/ast/sqlitecreateview.h"
#include "common/strhash.h"
class API_EXPORT TableModifier
{
public:
TableModifier(Db* db, const QString& table);
TableModifier(Db* db, const QString& database, const QString& table);
void alterTable(SqliteCreateTablePtr newCreateTable);
QStringList generateSqls() const;
bool isValid() const;
QStringList getErrors() const;
QStringList getWarnings() const;
QStringList getModifiedTables() const;
QStringList getModifiedIndexes() const;
QStringList getModifiedTriggers() const;
QStringList getModifiedViews() const;
bool hasMessages() const;
private:
void init();
void parseDdl();
QString getTempTableName();
void copyDataTo(const QString& targetTable, const QStringList& srcCols, const QStringList& dstCols);
void renameTo(const QString& newName, bool doCopyData = true);
QString renameToTemp(bool doCopyData = true);
void copyDataTo(const QString& table);
void copyDataTo(SqliteCreateTablePtr newCreateTable);
void handleIndexes();
void handleIndex(SqliteCreateIndexPtr index);
void handleTriggers();
void handleTrigger(SqliteCreateTriggerPtr trigger);
void handleTriggerQueries(SqliteCreateTriggerPtr trigger);
void handleViews();
void handleView(SqliteCreateViewPtr view);
SqliteQuery* handleTriggerQuery(SqliteQuery* query, const QString& trigName, const QString& trigTable);
SqliteSelect* handleSelect(SqliteSelect* select, const QString& trigTable = QString());
SqliteUpdate* handleTriggerUpdate(SqliteUpdate* update, const QString& trigName, const QString& trigTable);
SqliteInsert* handleTriggerInsert(SqliteInsert* insert, const QString& trigName, const QString& trigTable);
SqliteDelete* handleTriggerDelete(SqliteDelete* del, const QString& trigName, const QString& trigTable);
StrHash<SelectResolver::Table> tablesAsNameHash(const QSet<SelectResolver::Table> &resolvedTables);
bool isTableAliasUsedForColumn(const TokenPtr& token, const StrHash<SelectResolver::Table>& resolvedTables, const QList<SqliteSelect::Core::SingleSource*>& selSources);
bool handleSubSelects(SqliteStatement* stmt, const QString& trigTable);
bool handleExprWithSelect(SqliteExpr* expr, const QString& trigTable);
bool handleAllExprWithTrigTable(SqliteStatement* stmt, const QString& contextTable);
bool handleExprListWithTrigTable(const QList<SqliteExpr*>& exprList);
bool handleExprWithTrigTable(SqliteExpr* expr);
bool handleExpr(SqliteExpr* expr);
void simpleHandleIndexes();
void simpleHandleTriggers(const QString& view = QString());
SqliteQueryPtr parseQuery(const QString& ddl);
/**
* @brief alterTableHandleFks
* @param newCreateTable
* Finds all tables referencing currently modified table and updates their referenced table name and columns.
*/
void handleFks();
void handleFkAsSubModifier(const QString& oldName, const QString& theNewName);
bool handleFkStmt(SqliteForeignKey* fk, const QString& oldName, const QString& theNewName);
bool handleFkConstrains(SqliteCreateTable* stmt, const QString& oldName, const QString& theNewName);
bool handleName(const QString& oldName, QString& valueToUpdate);
static bool handleName(const QString& oldName, const QString& theNewName, QString& valueToUpdate);
bool handleIndexedColumns(const QList<SqliteOrderBy*>& columnsToUpdate);
bool handleIndexedColumnsInitial(SqliteOrderBy* col, bool& modified);
bool handleIndexedColumnsInitial(SqliteIndexedColumn* col, bool& modified);
bool handleColumnNames(QStringList& columnsToUpdate);
bool handleColumnTokens(TokenList& columnsToUpdate);
bool handleUpdateColumns(SqliteUpdate* update);
QStringList handleUpdateColumns(const QStringList& colNames, bool& modified);
QString handleUpdateColumn(const QString& colName, bool& modified);
QList<SqliteCreateTable::Column*> getColumnsToCopyData(SqliteCreateTablePtr newCreateTable);
template <class T>
bool handleIndexedColumns(QList<T*>& columnsToUpdate)
{
bool modified = false;
QString lowerName;
QString colName;
QMutableListIterator<T*> it(columnsToUpdate);
while (it.hasNext())
{
T* idxCol = it.next();
if (handleIndexedColumnsInitial(idxCol, modified))
continue;
colName = idxCol->getColumnName();
// If column was modified, assign new name
lowerName = colName.toLower();
if (tableColMap.contains(lowerName))
{
idxCol->setColumnName(tableColMap[lowerName]);
modified = true;
continue;
}
// It wasn't modified, but it's not on existing columns list? Remove it.
if (indexOf(existingColumns, colName, Qt::CaseInsensitive) == -1)
{
it.remove();
modified = true;
}
}
return modified;
}
Db* db = nullptr;
/**
* @brief Database name. The "main" is default.
* Other databases (temp, attached...) are not supported at the moment.
*/
QString database;
/**
* @brief Current table name (after renaming)
*/
QString table;
/**
* @brief Initial table name, before any renaming.
*/
QString originalTable;
/**
* @brief createTable Original DDL.
*/
SqliteCreateTablePtr createTable;
/**
* @brief Statements to be executed to make changes real.
*/
QStringList sqls;
QStringList warnings;
QStringList errors;
QString newName;
QStringList existingColumns;
QHash<QString, QString> tableColMap;
QHash<QString, QString> triggerNameToDdlMap;
QStringList tablesHandledForFk;
QStringList modifiedTables;
QStringList modifiedIndexes;
QStringList modifiedTriggers;
QStringList modifiedViews;
QStringList usedTempTableNames;
};
#endif // TABLEMODIFIER_H
|