#include "sqliteupsert.h" #include "common/global.h" #include "parser/ast/sqliteorderby.h" #include "parser/ast/sqliteexpr.h" #include "parser/statementtokenbuilder.h" #include SqliteUpsert::SqliteUpsert() { doNothing = true; } SqliteUpsert::SqliteUpsert(const QList& 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& conflictColumns, SqliteExpr* conflictWhere, const QList& 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()).withParRight(); else builder.withOther(keyVal.first.toString()); 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; }