aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/parser/ast
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2025-01-16 01:58:22 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2025-01-16 01:58:22 -0500
commita5ae79be08125b31bb6b8d9703090a98c6fd2e30 (patch)
tree569ee612c9de85b2bb423efa485688ef1d43852e /SQLiteStudio3/coreSQLiteStudio/parser/ast
parent21966b4f924b0a1933d9662e75ff253bd154fdb7 (diff)
parent81a21e6ce040e7740de86340c8ea4dba30e69bc3 (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')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp35
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h9
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp55
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h1
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp7
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp14
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h8
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