diff options
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser/ast')
15 files changed, 359 insertions, 87 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp index fdbadf8..5c11ff5 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp @@ -57,7 +57,7 @@ SqliteCreateIndex::SqliteCreateIndex(bool unique, bool ifNotExists, const QStrin table = name3; this->indexedColumns = columns; - foreach (SqliteOrderBy* idxCol, columns) + for (SqliteOrderBy* idxCol : columns) idxCol->setParent(this); this->where = where; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp index 2ac6c04..eb4ae85 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp @@ -22,11 +22,10 @@ SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString { init(ifNotExistsKw, temp, name1, name2); this->columns = columns; - foreach (Column* column, columns) + for (Column* column : columns) column->setParent(this); - SqliteCreateTable::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) { if (this->constraints.size() > 0 && this->constraints.last()->type == SqliteCreateTable::Constraint::NAME_ONLY) @@ -66,7 +65,7 @@ SqliteStatement*SqliteCreateTable::clone() QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getConstraints(SqliteCreateTable::Constraint::Type type) const { QList<SqliteCreateTable::Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == type) results << constr; @@ -75,11 +74,11 @@ QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getConstraints(SqliteCr SqliteStatement* SqliteCreateTable::getPrimaryKey() const { - foreach (Constraint* constr, getConstraints(Constraint::PRIMARY_KEY)) + for (Constraint* constr : getConstraints(Constraint::PRIMARY_KEY)) return constr; Column::Constraint* colConstr = nullptr; - foreach (Column* col, columns) + for (Column* col : columns) { colConstr = col->getConstraint(Column::Constraint::PRIMARY_KEY); if (colConstr) @@ -106,7 +105,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Constraint* tableConstr = dynamic_cast<SqliteCreateTable::Constraint*>(primaryKey); if (tableConstr) { - foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns) + for (SqliteIndexedColumn* idxCol : tableConstr->indexedColumns) colNames << idxCol->name; } return colNames; @@ -114,7 +113,7 @@ QStringList SqliteCreateTable::getPrimaryKeyColumns() const SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) { - foreach (Column* col, columns) + for (Column* col : columns) { if (col->name.compare(colName, Qt::CaseInsensitive) == 0) return col; @@ -125,7 +124,7 @@ SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName) QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getForeignKeysByTable(const QString& foreignTable) const { QList<Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -135,7 +134,7 @@ QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getForeignKeysByTable(c QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::getColumnForeignKeysByTable(const QString& foreignTable) const { QList<Column::Constraint*> results; - foreach (Column* col, columns) + for (Column* col : columns) results += col->getForeignKeysByTable(foreignTable); return results; @@ -144,7 +143,7 @@ QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::getColumnForeig QStringList SqliteCreateTable::getColumnNames() const { QStringList names; - foreach (Column* col, columns) + for (Column* col : columns) names << col->name; return names; @@ -154,7 +153,7 @@ QHash<QString, QString> SqliteCreateTable::getModifiedColumnsMap(bool lowercaseK { QHash<QString, QString> colMap; QString key; - foreach (Column* col, columns) + for (Column* col : columns) { key = lowercaseKeys ? col->originalName.toLower() : col->originalName; if (col->name.compare(col->originalName, cs) != 0) @@ -385,10 +384,10 @@ void SqliteCreateTable::Column::Constraint::initFk(const QString& table, const Q foreignKey = fk; fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); } @@ -466,7 +465,7 @@ void SqliteCreateTable::Constraint::initPk(const QList<SqliteIndexedColumn *> &i autoincrKw = autoincr; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -476,7 +475,7 @@ void SqliteCreateTable::Constraint::initUnique(const QList<SqliteIndexedColumn * this->indexedColumns = indexedColumns; onConflict = algo; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); } @@ -499,7 +498,7 @@ void SqliteCreateTable::Constraint::initFk(const QList<SqliteIndexedColumn *> &i this->type = SqliteCreateTable::Constraint::FOREIGN_KEY; this->indexedColumns = indexedColumns; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) idxCol->setParent(this); SqliteForeignKey* fk = new SqliteForeignKey(); @@ -511,10 +510,10 @@ void SqliteCreateTable::Constraint::initFk(const QList<SqliteIndexedColumn *> &i fk->setParent(this); - foreach (SqliteIndexedColumn* idxCol, fkColumns) + for (SqliteIndexedColumn* idxCol : fkColumns) idxCol->setParent(fk); - foreach (SqliteForeignKey::Condition* cond, conditions) + for (SqliteForeignKey::Condition* cond : conditions) cond->setParent(fk); this->foreignKey = fk; @@ -528,7 +527,7 @@ bool SqliteCreateTable::Constraint::doesAffectColumn(const QString& columnName) int SqliteCreateTable::Constraint::getAffectedColumnIdx(const QString& columnName) { int i = 0; - foreach (SqliteIndexedColumn* idxCol, indexedColumns) + for (SqliteIndexedColumn* idxCol : indexedColumns) { if (idxCol->name.compare(columnName, Qt::CaseInsensitive) == 0) return i; @@ -619,8 +618,7 @@ SqliteCreateTable::Column::Column(const QString &name, SqliteColumnType *type, c if (type) type->setParent(this); - SqliteCreateTable::Column::Constraint* constr = nullptr; - foreach (constr, constraints) + for (SqliteCreateTable::Column::Constraint* constr : constraints) { // If last constraint on list is NAME_ONLY we apply the name // to current constraint and remove NAME_ONLY. @@ -689,7 +687,7 @@ QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::Column::getCons QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::Column::getForeignKeysByTable(const QString& foreignTable) const { QList<Constraint*> results; - foreach (Constraint* constr, constraints) + for (Constraint* constr : constraints) if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0) results << constr; @@ -748,7 +746,7 @@ TokenList SqliteCreateTable::Column::Constraint::rebuildTokensFromContents() { builder.withKeyword("DEFAULT").withSpace(); if (!id.isNull()) - builder.withOther(id); + builder.withOther(id, dialect); else if (!ctime.isNull()) builder.withKeyword(ctime.toUpper()); else if (expr) diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp index e15ddd6..001dd2d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp @@ -22,7 +22,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(const SqliteCreateTrigger& other) : // Special case of deep collection copy SqliteQuery* newQuery = nullptr; - foreach (SqliteQuery* query, other.queries) + for (SqliteQuery* query : other.queries) { switch (query->queryType) { @@ -95,7 +95,7 @@ SqliteCreateTrigger::SqliteCreateTrigger(int temp, bool ifNotExists, const QStri if (when) when->setParent(this); - foreach (SqliteQuery* q, queries) + for (SqliteQuery* q : queries) q->setParent(this); } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp index 5dc830b..d17205a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp @@ -269,7 +269,7 @@ void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, const QList<SqliteExpr*>& expr1 = expr; this->notKw = notKw; this->exprList = exprList; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -331,7 +331,7 @@ void SqliteExpr::initCase(SqliteExpr *expr1, const QList<SqliteExpr*>& exprList, if (expr2) expr2->setParent(this); - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) expr->setParent(this); } @@ -341,6 +341,28 @@ void SqliteExpr::initRaise(const QString& type, const QString& text) raiseFunction = new SqliteRaise(type, text); } +void SqliteExpr::detectDoubleQuotes(bool recursively) +{ + if (doubleQuotesChecked) + return; + + doubleQuotesChecked = true; + + if (tokens.size() > 0) + { + QString val = tokens.first()->value; + if (val[0] == '"' && val[0] == val[val.length() - 1]) + possibleDoubleQuotedString = true; + } + + for (SqliteStatement* stmt : childStatements()) + { + SqliteExpr* subExpr = dynamic_cast<SqliteExpr*>(stmt); + if (subExpr) + subExpr->detectDoubleQuotes(recursively); + } +} + QStringList SqliteExpr::getColumnsInStatement() { return getStrListFromValue(column); @@ -533,12 +555,7 @@ TokenList SqliteExpr::rebuildTokensFromContents() void SqliteExpr::evaluatePostParsing() { - if (tokens.size() > 0) - { - QString val = tokens.first()->value; - if (val[0] == '"' && val[0] == val[val.length() - 1]) - possibleDoubleQuotedString = true; - } + detectDoubleQuotes(false); // not recursively, as SqliteStatement will take care of recursiveness } TokenList SqliteExpr::rebuildId() @@ -550,7 +567,7 @@ TokenList SqliteExpr::rebuildId() if (!table.isNull()) builder.withOther(table, dialect).withOperator("."); - if (possibleDoubleQuotedString) + if (table.isNull() && possibleDoubleQuotedString) builder.withStringPossiblyOther(column, dialect); else builder.withOther(column, dialect); @@ -652,7 +669,7 @@ TokenList SqliteExpr::rebuildCase() builder.withSpace(); bool then = false; - foreach (SqliteExpr* expr, exprList) + for (SqliteExpr* expr : exprList) { if (then) builder.withKeyword("THEN"); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h index 4d5bb03..c65a8e2 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h @@ -92,6 +92,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void initSubSelect(SqliteSelect* select); void initCase(SqliteExpr* expr1, const QList<SqliteExpr*>& exprList, SqliteExpr* expr2); void initRaise(const QString& type, const QString& text = QString::null); + void detectDoubleQuotes(bool recursively = true); Mode mode = Mode::null; QVariant literalValue = QVariant(); @@ -132,6 +133,7 @@ class API_EXPORT SqliteExpr : public SqliteStatement void evaluatePostParsing(); private: + bool doubleQuotesChecked = false; TokenList rebuildId(); TokenList rebuildLike(); TokenList rebuildNotNull(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp index cb85377..e48cffb 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp @@ -5,6 +5,7 @@ #include "parser/statementtokenbuilder.h" #include "common/global.h" #include "sqlitewith.h" +#include "sqliteupsert.h" SqliteInsert::SqliteInsert() { @@ -18,6 +19,7 @@ SqliteInsert::SqliteInsert(const SqliteInsert& other) : DEEP_COPY_COLLECTION(SqliteExpr, values); DEEP_COPY_FIELD(SqliteSelect, select); DEEP_COPY_FIELD(SqliteWith, with); + DEEP_COPY_FIELD(SqliteUpsert, upsert); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns, @@ -33,12 +35,12 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); - foreach (SqliteExpr* expr, row) + for (SqliteExpr* expr : row) expr->setParent(this); } SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns, - SqliteSelect *select, SqliteWith* with) : + SqliteSelect *select, SqliteWith* with, SqliteUpsert* upsert) : SqliteInsert() { initName(name1, name2); @@ -48,6 +50,10 @@ SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QS if (with) with->setParent(this); + this->upsert = upsert; + if (upsert) + upsert->setParent(this); + columnNames = columns; this->select = select; if (select) @@ -98,7 +104,7 @@ QStringList SqliteInsert::getDatabasesInStatement() TokenList SqliteInsert::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist_opt", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist_opt", -1)) { if (token->type != Token::OTHER && token->type != Token::KEYWORD) continue; @@ -201,6 +207,8 @@ TokenList SqliteInsert::rebuildTokensFromContents() if (select) { builder.withStatement(select); + if (upsert) + builder.withSpace().withStatement(upsert); } else if (dialect == Dialect::Sqlite2) // Sqlite2 uses classic single row values { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h index 4287680..2ee4965 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h @@ -9,6 +9,7 @@ class SqliteSelect; class SqliteExpr; class SqliteWith; +class SqliteUpsert; class API_EXPORT SqliteInsert : public SqliteQuery { @@ -19,7 +20,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery const QString& name2, const QList<QString>& columns, const QList<SqliteExpr*>& row, SqliteWith* with); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, - const QString& name2, const QList<QString>& columns, SqliteSelect* select, SqliteWith* with); + const QString& name2, const QList<QString>& columns, SqliteSelect* select, SqliteWith* with, SqliteUpsert* upsert = nullptr); SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, const QList<QString>& columns, SqliteWith* with); ~SqliteInsert(); @@ -50,6 +51,7 @@ class API_EXPORT SqliteInsert : public SqliteQuery QList<SqliteExpr*> values; SqliteSelect* select = nullptr; SqliteWith* with = nullptr; + SqliteUpsert* upsert = nullptr; }; typedef QSharedPointer<SqliteInsert> SqliteInsertPtr; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp index f1b1929..8038cb6 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp @@ -50,7 +50,7 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO Core::ResultColumn* resCol = nullptr; QList<Core::ResultColumn*> resColList; - foreach (const QList<SqliteExpr*>& singleValues, values) + for (const QList<SqliteExpr*>& singleValues : values) { Core* core = new Core(); core->setParent(select); @@ -64,9 +64,10 @@ SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundO select->coreSelects << core; resColList.clear(); - foreach (SqliteExpr* value, singleValues) + for (SqliteExpr* value : singleValues) { resCol = new Core::ResultColumn(value, false, QString::null); + value->detectDoubleQuotes(); // invoke explicitly before rebuilding tokens not to lose this information resCol->rebuildTokens(); resCol->setParent(core); core->resultColumns << resCol; @@ -116,7 +117,7 @@ SqliteSelect::CompoundOperator SqliteSelect::compoundOperator(const QString& op) void SqliteSelect::reset() { - foreach (Core* core, coreSelects) + for (Core* core : coreSelects) delete core; coreSelects.clear(); @@ -172,13 +173,13 @@ SqliteSelect::Core::Core(int distinct, const QList<ResultColumn *> &resCols, Sql if (limit) limit->setParent(this); - foreach (SqliteOrderBy* order, orderBy) + for (SqliteOrderBy* order : orderBy) order->setParent(this); - foreach (SqliteExpr* expr, groupBy) + for (SqliteExpr* expr : groupBy) expr->setParent(this); - foreach (SqliteSelect::Core::ResultColumn* resCol, resCols) + for (SqliteSelect::Core::ResultColumn* resCol : resCols) resCol->setParent(this); } @@ -293,6 +294,24 @@ SqliteSelect::Core::SingleSource::SingleSource(const QString& name1, const QStri this->notIndexedKw = notIndexedKw; } +SqliteSelect::Core::SingleSource::SingleSource(const QString &name1, const QString &name2, bool asKw, const QString &alias, const QList<SqliteExpr*> &exprList) +{ + if (!name2.isNull()) + { + database = name1; + funcName = name2; + } + else + funcName = name1; + + funcParams.append(exprList); + for (SqliteExpr* expr : exprList) + expr->setParent(this); + + this->asKw = asKw; + this->alias = alias; +} + SqliteSelect::Core::SingleSource::SingleSource(SqliteSelect *select, bool asKw, const QString &alias) { this->select = select; @@ -409,7 +428,7 @@ QStringList SqliteSelect::Core::JoinConstraint::getColumnsInStatement() TokenList SqliteSelect::Core::JoinConstraint::getColumnTokensInStatement() { TokenList list; - foreach (TokenPtr token, getTokenListFromNamedKey("inscollist", -1)) + for (TokenPtr token : getTokenListFromNamedKey("idlist", -1)) { if (token->type == Token::OPERATOR) // a COMMA continue; @@ -539,7 +558,7 @@ SqliteSelect::Core::JoinSource::JoinSource(SqliteSelect::Core::SingleSource *sin if (singleSource) singleSource->setParent(this); - foreach (JoinSourceOther* other, otherSources) + for (JoinSourceOther* other : otherSources) other->setParent(this); } @@ -590,12 +609,27 @@ TokenList SqliteSelect::Core::SingleSource::rebuildTokensFromContents() builder.withSpace().withKeyword("AS"); builder.withSpace().withOther(alias, dialect); + } + } + else if (!funcName.isNull()) + { + if (!database.isNull()) + builder.withOther(database, dialect).withOperator("."); - if (indexedByKw) - builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); - else if (notIndexedKw) - builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); + builder.withOther(funcName, dialect).withParLeft().withStatementList(funcParams).withParRight(); + + if (!alias.isNull()) + { + if (asKw) + builder.withSpace().withKeyword("AS"); + + builder.withSpace().withOther(alias, dialect); } + + if (indexedByKw) + builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect); + else if (notIndexedKw) + builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED"); } else if (select) { @@ -723,7 +757,11 @@ TokenList SqliteSelect::Core::rebuildTokensFromContents() StatementTokenBuilder builder; if (valuesMode) { - builder.withKeyword("VALUES").withSpace().withParLeft().withStatementList(resultColumns).withParRight(); + SqliteSelect* select = dynamic_cast<SqliteSelect*>(parentStatement()); + if (select->coreSelects.indexOf(this) == 0) // this is first core in series of cores of values mode of the SELECT + builder.withKeyword("VALUES").withSpace(); + + builder.withParLeft().withStatementList(resultColumns).withParRight(); return builder.build(); } @@ -763,7 +801,7 @@ TokenList SqliteSelect::rebuildTokensFromContents() if (with) builder.withStatement(with); - foreach (SqliteSelect::Core* core, coreSelects) + for (SqliteSelect::Core* core : coreSelects) { if (core->compoundOp == CompoundOperator::UNION_ALL) { diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h index 22d1921..b6f537d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h @@ -63,6 +63,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery SingleSource(const SingleSource& other); SingleSource(const QString& name1, const QString& name2, bool asKw, const QString& alias, bool notIndexedKw, const QString& indexedBy); + SingleSource(const QString& name1, const QString& name2, + bool asKw, const QString& alias, const QList<SqliteExpr*>& exprList); SingleSource(SqliteSelect* select, bool asKw, const QString& alias); SingleSource(JoinSource* src, bool asKw, const QString& alias); @@ -71,6 +73,8 @@ class API_EXPORT SqliteSelect : public SqliteQuery QString database = QString::null; QString table = QString::null; QString alias = QString::null; + QString funcName = QString::null; + QList<SqliteExpr*> funcParams; bool asKw = false; bool indexedByKw = false; bool notIndexedKw = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp index f14273d..119461a 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp @@ -90,7 +90,7 @@ QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(bool c void SqliteStatement::setSqliteDialect(Dialect dialect) { this->dialect = dialect; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->setSqliteDialect(dialect); } @@ -106,14 +106,14 @@ SqliteStatementPtr SqliteStatement::detach() void SqliteStatement::processPostParsing() { evaluatePostParsing(); - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) stmt->processPostParsing(); } QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getColumnsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumns(this, checkParent, checkChilds); return results; @@ -122,7 +122,7 @@ QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool che QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getTablesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTables(this, checkParent, checkChilds); return results; @@ -131,7 +131,7 @@ QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool chec QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool checkParent, bool checkChilds) { QStringList results = getDatabasesInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabases(this, checkParent, checkChilds); return results; @@ -140,7 +140,7 @@ QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getColumnTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextColumnTokens(this, checkParent, checkChilds); return results; @@ -149,7 +149,7 @@ TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getTableTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextTableTokens(this, checkParent, checkChilds); return results; @@ -158,7 +158,7 @@ TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool c TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, bool checkParent, bool checkChilds) { TokenList results = getDatabaseTokensInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) results += stmt->getContextDatabaseTokens(this, checkParent, checkChilds); return results; @@ -167,7 +167,7 @@ TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, boo QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(SqliteStatement* caller, bool checkParent, bool checkChilds) { QList<SqliteStatement::FullObject> results = getFullObjectsInStatement(); - foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds)) + for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) { stmt->setContextDbForFullObject(dbTokenForFullObjects); results += stmt->getContextFullObjects(this, checkParent, checkChilds); @@ -231,12 +231,12 @@ QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement * if (checkChilds) { - foreach (stmt, childStatements()) + for (SqliteStatement* childStmt : childStatements()) { - if (stmt == caller) + if (childStmt == caller) continue; - results += stmt; + results += childStmt; } } @@ -246,7 +246,7 @@ QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement * TokenList SqliteStatement::extractPrintableTokens(const TokenList &tokens, bool skipMeaningless) { TokenList list; - foreach (TokenPtr token, tokens) + for (TokenPtr token : tokens) { switch (token->type) { @@ -488,7 +488,7 @@ Range SqliteStatement::getRange() SqliteStatement *SqliteStatement::findStatementWithToken(TokenPtr token) { SqliteStatement* stmtWithToken = nullptr; - foreach (SqliteStatement* stmt, childStatements()) + for (SqliteStatement* stmt : childStatements()) { stmtWithToken = stmt->findStatementWithToken(token); if (stmtWithToken) @@ -521,7 +521,7 @@ SqliteStatement *SqliteStatement::parentStatement() QList<SqliteStatement *> SqliteStatement::childStatements() { QList<SqliteStatement*> results; - foreach (QObject* obj, children()) + for (QObject* obj : children()) results += dynamic_cast<SqliteStatement*>(obj); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h index bacb2d7..779bea3 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h @@ -249,7 +249,7 @@ class API_EXPORT SqliteStatement : public QObject if (casted) results << casted; - foreach (SqliteStatement* stmt, getContextStatements(this, false, true)) + for (SqliteStatement* stmt : getContextStatements(this, false, true)) results += stmt->getAllTypedStatements<T>(); return results; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp index df892fb..2063e0e 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp @@ -17,7 +17,7 @@ SqliteUpdate::SqliteUpdate(const SqliteUpdate& other) : { // Special case of deep collection copy SqliteExpr* newExpr = nullptr; - foreach (const ColumnAndValue& keyValue, other.keyValueMap) + for (const ColumnAndValue& keyValue : other.keyValueMap) { newExpr = new SqliteExpr(*keyValue.second); newExpr->setParent(this); @@ -33,7 +33,7 @@ SqliteUpdate::~SqliteUpdate() } SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, bool notIndexedKw, const QString &indexedBy, - const QList<QPair<QString,SqliteExpr*> > values, SqliteExpr *where, SqliteWith* with) + const QList<ColumnAndValue>& values, SqliteExpr *where, SqliteWith* with) : SqliteUpdate() { this->onConflict = onConflict; @@ -59,7 +59,7 @@ SqliteUpdate::SqliteUpdate(SqliteConflictAlgo onConflict, const QString &name1, if (with) with->setParent(this); - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) keyValue.second->setParent(this); } @@ -70,7 +70,7 @@ SqliteStatement*SqliteUpdate::clone() SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) { - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { if (keyValue.first == column) return keyValue.second; @@ -81,8 +81,13 @@ SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column) QStringList SqliteUpdate::getColumnsInStatement() { QStringList columns; - foreach (const ColumnAndValue& keyValue, keyValueMap) - columns += keyValue.first; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } return columns; } @@ -105,20 +110,26 @@ TokenList SqliteUpdate::getColumnTokensInStatement() // for each 'expr' we get its first token, then locate it // in entire "setlist", get back 2 tokens to get what's before "=". TokenList list; - TokenList setListTokens = getTokenListFromNamedKey("setlist"); + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); int setListTokensSize = setListTokens.size(); - int colNameTokenIdx; + int end; + int start = 0; SqliteExpr* expr = nullptr; - foreach (const ColumnAndValue& keyValue, keyValueMap) + for (const ColumnAndValue& keyValue : keyValueMap) { expr = keyValue.second; - colNameTokenIdx = setListTokens.indexOf(expr->tokens[0]) - 2; - if (colNameTokenIdx < 0 || colNameTokenIdx > setListTokensSize) + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) { qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; continue; } - list << setListTokens[colNameTokenIdx]; + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); } return list; } @@ -189,12 +200,17 @@ TokenList SqliteUpdate::rebuildTokensFromContents() builder.withKeyword("SET").withSpace(); bool first = true; - foreach (const ColumnAndValue& keyVal, keyValueMap) + for (const ColumnAndValue& keyVal : keyValueMap) { if (!first) builder.withOperator(",").withSpace(); - builder.withOther(keyVal.first, dialect).withSpace().withOperator("=").withStatement(keyVal.second); + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); first = false; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h index 7d6e0c1..642473c 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h @@ -13,13 +13,13 @@ class SqliteWith; class API_EXPORT SqliteUpdate : public SqliteQuery { public: - typedef QPair<QString,SqliteExpr*> ColumnAndValue; + typedef QPair<QVariant,SqliteExpr*> ColumnAndValue; SqliteUpdate(); SqliteUpdate(const SqliteUpdate& other); ~SqliteUpdate(); SqliteUpdate(SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, - bool notIndexedKw, const QString& indexedBy, const QList<QPair<QString,SqliteExpr*> > values, + bool notIndexedKw, const QString& indexedBy, const QList<ColumnAndValue>& values, SqliteExpr* where, SqliteWith* with); SqliteStatement* clone(); diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp new file mode 100644 index 0000000..ced9c2d --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp @@ -0,0 +1,152 @@ +#include "sqliteupsert.h" +#include "common/global.h" +#include "parser/ast/sqliteorderby.h" +#include "parser/ast/sqliteexpr.h" +#include "parser/statementtokenbuilder.h" +#include <QDebug> + +SqliteUpsert::SqliteUpsert() +{ + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = true; +} + +SqliteUpsert::SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere, const QList<ColumnAndValue>& values, SqliteExpr* setWhere) +{ + this->conflictColumns = conflictColumns; + this->conflictWhere = conflictWhere; + this->keyValueMap = values; + this->setWhere = setWhere; + + if (this->conflictWhere) + this->conflictWhere->setParent(this); + + if (this->setWhere) + this->setWhere->setParent(this); + + for (SqliteOrderBy* idxCol : conflictColumns) + idxCol->setParent(this); + + doNothing = false; +} + +SqliteUpsert::SqliteUpsert(const SqliteUpsert& other) + : SqliteStatement(other), doNothing(other.doNothing) +{ + DEEP_COPY_COLLECTION(SqliteOrderBy, conflictColumns); + + // Special case of deep collection copy + SqliteExpr* newExpr = nullptr; + for (const ColumnAndValue& keyValue : other.keyValueMap) + { + newExpr = new SqliteExpr(*keyValue.second); + newExpr->setParent(this); + keyValueMap << ColumnAndValue(keyValue.first, newExpr); + } + + DEEP_COPY_FIELD(SqliteExpr, conflictWhere); + DEEP_COPY_FIELD(SqliteExpr, setWhere); +} + +SqliteStatement* SqliteUpsert::clone() +{ + return new SqliteUpsert(*this); +} + +TokenList SqliteUpsert::rebuildTokensFromContents() +{ + StatementTokenBuilder builder; + + builder.withKeyword("ON").withSpace().withKeyword("CONFLICT"); + if (!conflictColumns.isEmpty()) + { + builder.withSpace().withParLeft().withStatementList(conflictColumns).withParRight(); + if (conflictWhere) + builder.withSpace().withKeyword("WHERE").withStatement(conflictWhere); + } + + builder.withSpace().withKeyword("DO").withSpace(); + + if (doNothing) + { + builder.withKeyword("NOTHING"); + } + else + { + builder.withKeyword("UPDATE").withSpace().withKeyword("SET").withSpace(); + bool first = true; + for (const ColumnAndValue& keyVal : keyValueMap) + { + if (!first) + builder.withOperator(",").withSpace(); + + if (keyVal.first.type() == QVariant::StringList) + builder.withParLeft().withOtherList(keyVal.first.toStringList(), dialect).withParRight(); + else + builder.withOther(keyVal.first.toString(), dialect); + + builder.withSpace().withOperator("=").withStatement(keyVal.second); + first = false; + } + + if (setWhere) + builder.withSpace().withKeyword("WHERE").withStatement(setWhere); + } + + return builder.build(); +} + +QStringList SqliteUpsert::getColumnsInStatement() +{ + QStringList columns; + for (const ColumnAndValue& keyValue : keyValueMap) + { + if (keyValue.first.type() == QVariant::StringList) + columns += keyValue.first.toStringList(); + else + columns += keyValue.first.toString(); + } + + return columns; +} + +TokenList SqliteUpsert::getColumnTokensInStatement() +{ + // Alrorithm same as in UPDATE. See comments there for details. + TokenList list; + TokenList setListTokens = getTokenListFromNamedKey("setlist", -1); + int setListTokensSize = setListTokens.size(); + int end; + int start = 0; + SqliteExpr* expr = nullptr; + for (const ColumnAndValue& keyValue : keyValueMap) + { + expr = keyValue.second; + end = setListTokens.indexOf(expr->tokens[0]); + if (end < 0 || end >= setListTokensSize) + { + qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement()."; + continue; + } + + // Before expression tokens there will be only column(s) token(s) + // and commans, and equal operator. Let's take only ID tokens, which are columns. + list += setListTokens.mid(start, end - start - 1).filter(Token::OTHER); + + start = end + expr->tokens.size(); + } + return list; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h new file mode 100644 index 0000000..4a245cd --- /dev/null +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h @@ -0,0 +1,35 @@ +#ifndef SQLITEUPSERT_H +#define SQLITEUPSERT_H + + +#include "sqlitestatement.h" +#include "sqliteindexedcolumn.h" + +class SqliteExpr; +class SqliteOrderBy; + +class SqliteUpsert : public SqliteStatement +{ + public: + typedef QPair<QVariant,SqliteExpr*> ColumnAndValue; + + SqliteUpsert(); + SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere); + SqliteUpsert(const QList<SqliteOrderBy*>& conflictColumns, SqliteExpr* conflictWhere, const QList<ColumnAndValue>& values, SqliteExpr* setWhere); + SqliteUpsert(const SqliteUpsert& other); + + SqliteStatement* clone(); + + QList<SqliteOrderBy*> conflictColumns; + SqliteExpr* conflictWhere = nullptr; + QList<ColumnAndValue> keyValueMap; + SqliteExpr* setWhere = nullptr; + bool doNothing = false; + + protected: + TokenList rebuildTokensFromContents(); + QStringList getColumnsInStatement(); + TokenList getColumnTokensInStatement(); +}; + +#endif // SQLITEUPSERT_H |
