diff options
| author | 2025-01-16 01:58:22 -0500 | |
|---|---|---|
| committer | 2025-01-16 01:58:22 -0500 | |
| commit | a5ae79be08125b31bb6b8d9703090a98c6fd2e30 (patch) | |
| tree | 569ee612c9de85b2bb423efa485688ef1d43852e /SQLiteStudio3/coreSQLiteStudio/parser/ast | |
| parent | 21966b4f924b0a1933d9662e75ff253bd154fdb7 (diff) | |
| parent | 81a21e6ce040e7740de86340c8ea4dba30e69bc3 (diff) | |
Update upstream source from tag 'upstream/3.4.13+dfsg'
Update to upstream version '3.4.13+dfsg'
with Debian dir bf81ee0219cb8e4562a4751df17d75814772d2d6
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser/ast')
7 files changed, 117 insertions, 12 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp index fff4036..165a5fc 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp @@ -701,12 +701,15 @@ SqliteCreateTable::Column::Column(const QString &name, SqliteColumnType *type, c this->constraints.last()->type != SqliteCreateTable::Column::Constraint::NAME_ONLY) { SqliteCreateTable::Column::Constraint* last = this->constraints.last(); - last->foreignKey->deferrable = constr->deferrable; - last->foreignKey->initially = constr->initially; - delete constr; - - // We don't want deleted constr to be added to list. We finish this now. - continue; + if (last->type == Constraint::FOREIGN_KEY) + { + last->foreignKey->deferrable = constr->deferrable; + last->foreignKey->initially = constr->initially; + delete constr; + + // We don't want deleted constr to be added to list. We finish this now. + continue; + } } this->constraints << constr; @@ -870,8 +873,26 @@ TokenList SqliteCreateTable::Column::Constraint::rebuildTokensFromContents() break; } case SqliteCreateTable::Column::Constraint::NULL_: - case SqliteCreateTable::Column::Constraint::NAME_ONLY: + { + // Is the default and unofficial. Pass through + builder.withKeyword("NULL"); + break; + } case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY: + { + // Pass through + if (deferrable == SqliteDeferrable::NOT_DEFERRABLE) + builder.withKeyword("NOT").withSpace(); + builder.withKeyword("DEFERRABLE"); + if (initially != SqliteInitially::null) + { + builder.withSpace().withKeyword("INITIALLY").withSpace(); + builder.withKeyword(initially == SqliteInitially::DEFERRED ? "DEFERRED" : "IMMEDIATE"); + } + break; + } + case SqliteCreateTable::Column::Constraint::NAME_ONLY: + // The CONSTRAINT <name> clause has already been output break; } diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h index 5d797c1..0507740 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h @@ -91,13 +91,14 @@ class API_EXPORT SqliteCreateTable : public SqliteQuery, public SqliteDdlWithDbC GeneratedType generatedType = GeneratedType::null; SqliteForeignKey* foreignKey = nullptr; + // DEFERRABLE_ONLY fields. A DEFERRABLE_ONLY pseudo-constraint following a + // a FK is merged to the FK at parse time. + SqliteDeferrable deferrable = SqliteDeferrable::null; + SqliteInitially initially = SqliteInitially::null; + protected: TokenList rebuildTokensFromContents(); - private: - SqliteDeferrable deferrable = SqliteDeferrable::null; // only a temporary field for parse time, before merging with actual FK - SqliteInitially initially = SqliteInitially::null; // only a temporary field for parse time, before merging with actual FK - }; typedef QSharedPointer<Constraint> ConstraintPtr; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp index 0e11619..36d5852 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp @@ -4,6 +4,7 @@ #include "parser/statementtokenbuilder.h" #include "common/global.h" #include "sqliteindexedcolumn.h" +#include <QDebug> SqliteCreateView::SqliteCreateView() { @@ -139,3 +140,57 @@ void SqliteCreateView::setObjectName(const QString& name) { view = name; } + +TokenList SqliteCreateView::equivalentSelectTokens() const +{ + if (columns.size() == 0) + return select->tokens; + + SqliteSelect::Core *core = select->coreSelects.first(); + bool hasStar = std::any_of(core->resultColumns.cbegin(), + core->resultColumns.cend(), + [](auto col) { return col->star; }); + bool useCTE = false; + if (!hasStar && columns.size() != core->resultColumns.size()) + { + qWarning() << "View with a column list clause and non-matching count of columns in SELECT. " + << "Expect an error if result column count does not match column list length."; + useCTE = true; + } + if (hasStar) + { + qWarning() << "View with a column list clause and SELECT *. " + << "Expect an error if result column count does not match column list length."; + useCTE = true; + } + if (useCTE) + { + StatementTokenBuilder builder; + builder.withKeyword("WITH").withSpace().withOther(view).withParLeft(); + bool first = true; + for (SqliteIndexedColumn *column : columns) + { + if (!first) + builder.withOperator(","); + first = false; + builder.withOther(column->name); + } + builder.withParRight().withKeyword("AS").withParLeft().withTokens(select->tokens).withParRight() + .withKeyword("SELECT").withSpace().withOperator("*").withSpace() + .withKeyword("FROM").withSpace().withOther(view); + return builder.build(); + } + + // There are no * in SELECT, and view column list length matches SELECT column list length. + // Apply view column names to SELECT as aliases. + SqliteSelect* selectCopy = dynamic_cast<SqliteSelect*>(select->clone()); + QList<SqliteSelect::Core::ResultColumn*> resultColumns = selectCopy->coreSelects.first()->resultColumns; + int n = 0; + for (SqliteSelect::Core::ResultColumn* column : resultColumns) + { + column->asKw = true; + column->alias = columns.at(n++)->name; + } + selectCopy->rebuildTokens(); + return selectCopy->tokens; +} diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h index 645532c..d90ce7d 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h @@ -23,6 +23,7 @@ class API_EXPORT SqliteCreateView : public SqliteQuery, public SqliteDdlWithDbCo void setTargetDatabase(const QString& database); QString getObjectName() const; void setObjectName(const QString& name); + TokenList equivalentSelectTokens() const; bool tempKw = false; bool temporaryKw = false; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp index 89c6b9b..7039970 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp @@ -456,6 +456,9 @@ QStringList SqliteExpr::getTablesInStatement() QStringList SqliteExpr::getDatabasesInStatement() { + if (database.isNull() && !table.isNull() && validDbNames.contains(table, Qt::CaseInsensitive)) + return getStrListFromValue(table); // it's a "db.", not a "db.table." + return getStrListFromValue(database); } @@ -494,7 +497,9 @@ TokenList SqliteExpr::getTableTokensInStatement() TokenList SqliteExpr::getDatabaseTokensInStatement() { TokenList list; - if (!database.isNull()) + if (database.isNull() && !table.isNull() && validDbNames.contains(table, Qt::CaseInsensitive)) + list << tokens[0]; // it's a "db.", not a "db.table." + else if (!database.isNull()) list << tokens[0]; return list; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp index d349a86..90d670b 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp @@ -2,6 +2,7 @@ #include "../token.h" #include "../lexer.h" #include "common/unused.h" +#include "services/dbmanager.h" #include <QDebug> SqliteStatement::SqliteStatement() @@ -35,6 +36,7 @@ QStringList SqliteStatement::getContextTables(bool checkParent, bool checkChilds QStringList SqliteStatement::getContextDatabases(bool checkParent, bool checkChilds) { + prepareDbNames(); return getContextDatabases(this, checkParent, checkChilds); } @@ -50,6 +52,7 @@ TokenList SqliteStatement::getContextTableTokens(bool checkParent, bool checkChi TokenList SqliteStatement::getContextDatabaseTokens(bool checkParent, bool checkChilds) { + prepareDbNames(); return getContextDatabaseTokens(this, checkParent, checkChilds); } @@ -125,7 +128,10 @@ QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool c { QStringList results = getDatabasesInStatement(); for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) + { + stmt->validDbNames = this->validDbNames; results += stmt->getContextDatabases(this, checkParent, checkChilds); + } return results; } @@ -152,7 +158,10 @@ TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, boo { TokenList results = getDatabaseTokensInStatement(); for (SqliteStatement* stmt : getContextStatements(caller, checkParent, checkChilds)) + { + stmt->validDbNames = this->validDbNames; results += stmt->getContextDatabaseTokens(this, checkParent, checkChilds); + } return results; } @@ -236,6 +245,11 @@ QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement * return results; } +void SqliteStatement::prepareDbNames() +{ + validDbNames = DBLIST->getValidDbNames(); +} + TokenList SqliteStatement::extractPrintableTokens(const TokenList &tokens, bool skipMeaningless) { TokenList list; diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h index 167321f..794b6de 100644 --- a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h +++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h @@ -333,8 +333,16 @@ class API_EXPORT SqliteStatement : public QObject */ TokenPtr dbTokenForFullObjects; + /** + * @brief List of database names as seen in the side Database List. + * It is resoled at top-level statement being queried for databases and then it's propagated down to all child statements. + * It helps to identify whether the xyz in "xyz." is a table or a database prefix. + */ + QStringList validDbNames; + private: QList<SqliteStatement*> getContextStatements(SqliteStatement* caller, bool checkParent, bool checkChilds); + void prepareDbNames(); }; #endif // SQLITESTATEMENT_H |
