aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/parser/ast
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser/ast')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp46
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp37
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp14
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp66
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp30
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h2
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp44
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h4
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.cpp152
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupsert.h35
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