aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/parser
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.cpp128
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.h46
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.cpp80
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.h29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.cpp63
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.h28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.cpp71
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.h38
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.cpp88
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.h30
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.cpp48
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.h25
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.cpp37
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.h20
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.cpp92
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.h32
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp190
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.h50
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp771
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h205
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp381
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.h96
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp120
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h35
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.cpp120
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.h42
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.cpp54
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.h27
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.cpp137
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.h45
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.cpp48
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.h27
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.cpp78
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.h29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.cpp86
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.h31
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.cpp79
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.h29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.cpp85
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.h29
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.cpp27
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.h19
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp644
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h144
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.cpp187
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.h75
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.cpp52
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.h30
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp214
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h57
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.cpp79
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.h31
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.cpp41
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.h28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.cpp109
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.h41
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.cpp51
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.h30
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.cpp66
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.h41
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.cpp70
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.h38
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.cpp82
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.h31
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.cpp39
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.h26
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.cpp57
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.h28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.cpp32
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.h25
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp783
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h228
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.cpp25
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.h17
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp553
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h339
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitetablerelatedddl.h14
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp207
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h51
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.cpp56
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.h28
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.cpp87
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.h45
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp324
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/keywords.h123
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/lempar.c1021
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp314
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/lexer.h254
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp470
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h27
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp323
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parser.h360
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.cpp45
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h118
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp184
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.h289
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parsererror.cpp44
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parsererror.h80
-rwxr-xr-xSQLiteStudio3/coreSQLiteStudio/parser/run_lemon.sh8
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp4650
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.h146
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y2068
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp5262
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h167
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y2406
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp206
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h290
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/token.cpp621
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/token.h733
109 files changed, 29009 insertions, 0 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.cpp
new file mode 100644
index 0000000..6c840e7
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.cpp
@@ -0,0 +1,128 @@
+#include "sqlitealtertable.h"
+#include "sqlitequerytype.h"
+#include "common/global.h"
+
+SqliteAlterTable::SqliteAlterTable()
+{
+ queryType = SqliteQueryType::AlterTable;
+}
+
+SqliteAlterTable::SqliteAlterTable(const SqliteAlterTable& other)
+ : SqliteQuery(other), command(other.command), newName(other.newName), database(other.database), table(other.table), columnKw(other.columnKw)
+{
+ DEEP_COPY_FIELD(SqliteCreateTable::Column, newColumn);
+}
+
+SqliteAlterTable::SqliteAlterTable(const QString &name1, const QString &name2, const QString &newName)
+ : SqliteAlterTable()
+{
+ command = Command::RENAME;
+ initName(name1, name2);
+ this->newName = newName;
+}
+
+SqliteAlterTable::SqliteAlterTable(const QString& name1, const QString& name2, bool columnKw, SqliteCreateTable::Column *column)
+ : SqliteAlterTable()
+{
+ command = Command::ADD_COLUMN;
+ initName(name1, name2);
+ this->columnKw = columnKw;
+ this->newColumn = column;
+ if (column)
+ column->setParent(this);
+}
+
+SqliteAlterTable::~SqliteAlterTable()
+{
+// if (newColumn)
+ // delete newColumn;
+}
+
+SqliteStatement* SqliteAlterTable::clone()
+{
+ return new SqliteAlterTable(*this);
+}
+
+QStringList SqliteAlterTable::getTablesInStatement()
+{
+ QStringList list;
+ if (!table.isNull())
+ list << table;
+
+ if (!newName.isNull())
+ list << newName;
+
+ return list;
+}
+
+QStringList SqliteAlterTable::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteAlterTable::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteAlterTable::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteAlterTable::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+ if (fullObj.isValid())
+ result << fullObj;
+
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+void SqliteAlterTable::initName(const QString &name1, const QString &name2)
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+TokenList SqliteAlterTable::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("ALTER").withSpace().withKeyword("TABLE").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table).withSpace();
+
+ if (newColumn)
+ {
+ builder.withKeyword("ADD").withSpace();
+ if (columnKw)
+ builder.withKeyword("COLUMN").withSpace();
+
+ builder.withStatement(newColumn);
+ }
+ else if (!newName.isNull())
+ {
+ builder.withKeyword("RENAME").withSpace().withKeyword("TO").withSpace().withOther(newName, dialect);
+ }
+
+ builder.withOperator(";");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.h
new file mode 100644
index 0000000..360db45
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitealtertable.h
@@ -0,0 +1,46 @@
+#ifndef SQLITEALTERTABLE_H
+#define SQLITEALTERTABLE_H
+
+#include "sqlitequery.h"
+#include "sqlitecreatetable.h"
+
+class API_EXPORT SqliteAlterTable : public SqliteQuery
+{
+ public:
+ enum class Command
+ {
+ RENAME,
+ ADD_COLUMN,
+ null
+ };
+
+ SqliteAlterTable();
+ SqliteAlterTable(const SqliteAlterTable& other);
+ SqliteAlterTable(const QString& name1, const QString& name2, const QString& newName);
+ SqliteAlterTable(const QString& name1, const QString& name2, bool columnKw, SqliteCreateTable::Column* column);
+ ~SqliteAlterTable();
+ SqliteStatement* clone();
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void initName(const QString& name1, const QString& name2);
+
+ public:
+ Command command = Command::null;
+ QString newName = QString::null;
+ QString database = QString::null;
+ QString table = QString::null;
+ bool columnKw = false;
+ SqliteCreateTable::Column* newColumn = nullptr;
+};
+
+typedef QSharedPointer<SqliteAlterTable> SqliteAlterTablePtr;
+
+#endif // SQLITEALTERTABLE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.cpp
new file mode 100644
index 0000000..d4e5778
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.cpp
@@ -0,0 +1,80 @@
+#include "sqliteanalyze.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteAnalyze::SqliteAnalyze()
+{
+ queryType = SqliteQueryType::Analyze;
+}
+
+SqliteAnalyze::SqliteAnalyze(const SqliteAnalyze& other) :
+ SqliteQuery(other), database(other.database), table(other.table)
+{
+}
+
+SqliteAnalyze::SqliteAnalyze(const QString &name1, const QString &name2)
+ : SqliteAnalyze()
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+SqliteStatement* SqliteAnalyze::clone()
+{
+ return new SqliteAnalyze(*this);
+}
+
+QStringList SqliteAnalyze::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteAnalyze::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteAnalyze::getTableTokensInStatement()
+{
+ return getObjectTokenListFromNmDbnm();
+}
+
+TokenList SqliteAnalyze::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteAnalyze::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ FullObject fullObj = getFullObjectFromNmDbnm(FullObject::TABLE);
+ if (fullObj.isValid())
+ result << fullObj;
+
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+
+TokenList SqliteAnalyze::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("ANALYZE").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table).withOperator(";");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.h
new file mode 100644
index 0000000..194e4c9
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteanalyze.h
@@ -0,0 +1,29 @@
+#ifndef SQLITEANALYZE_H
+#define SQLITEANALYZE_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteAnalyze : public SqliteQuery
+{
+ public:
+ SqliteAnalyze();
+ SqliteAnalyze(const SqliteAnalyze& other);
+ SqliteAnalyze(const QString& name1, const QString& name2);
+ SqliteStatement* clone();
+
+ QString database = QString::null;
+ QString table = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteAnalyze> SqliteAnalyzePtr;
+
+#endif // SQLITEANALYZE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.cpp
new file mode 100644
index 0000000..7d0b8a5
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.cpp
@@ -0,0 +1,63 @@
+#include "sqliteattach.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+
+SqliteAttach::SqliteAttach()
+{
+ queryType = SqliteQueryType::Attach;
+}
+
+SqliteAttach::SqliteAttach(bool dbKw, SqliteExpr *url, SqliteExpr *name, SqliteExpr *key)
+ : SqliteAttach()
+{
+ databaseKw = dbKw;
+ databaseUrl = url;
+ this->name = name;
+ this->key = key;
+
+ if (databaseUrl)
+ databaseUrl->setParent(this);
+
+ if (name)
+ name->setParent(this);
+
+ if (key)
+ key->setParent(this);
+}
+
+SqliteAttach::SqliteAttach(const SqliteAttach& other) :
+ SqliteQuery(other), databaseKw(other.databaseKw)
+{
+ DEEP_COPY_FIELD(SqliteExpr, databaseUrl);
+ DEEP_COPY_FIELD(SqliteExpr, name);
+ DEEP_COPY_FIELD(SqliteExpr, key);
+}
+
+SqliteAttach::~SqliteAttach()
+{
+}
+
+SqliteStatement* SqliteAttach::clone()
+{
+ return new SqliteAttach(*this);
+}
+
+TokenList SqliteAttach::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("ATTACH").withSpace();
+
+ if (databaseKw)
+ builder.withKeyword("DATABASE").withSpace();
+
+ builder.withStatement(databaseUrl).withSpace().withKeyword("AS").withSpace().withStatement(name);
+ if (key)
+ builder.withSpace().withKeyword("KEY").withSpace().withStatement(key);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.h
new file mode 100644
index 0000000..55151a5
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteattach.h
@@ -0,0 +1,28 @@
+#ifndef SQLITEATTACHDATABASE_H
+#define SQLITEATTACHDATABASE_H
+
+#include "sqlitequery.h"
+
+class SqliteExpr;
+
+class API_EXPORT SqliteAttach : public SqliteQuery
+{
+ public:
+ SqliteAttach();
+ SqliteAttach(const SqliteAttach& other);
+ SqliteAttach(bool dbKw, SqliteExpr* url, SqliteExpr* name, SqliteExpr* key);
+ ~SqliteAttach();
+ SqliteStatement* clone();
+
+ bool databaseKw = false;
+ SqliteExpr* databaseUrl = nullptr;
+ SqliteExpr* name = nullptr;
+ SqliteExpr* key = nullptr;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteAttach> SqliteAttachPtr;
+
+#endif // SQLITEATTACHDATABASE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.cpp
new file mode 100644
index 0000000..dcd9740
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.cpp
@@ -0,0 +1,71 @@
+#include "sqlitebegintrans.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteBeginTrans::SqliteBeginTrans()
+{
+ queryType = SqliteQueryType::BeginTrans;
+}
+
+SqliteBeginTrans::SqliteBeginTrans(const SqliteBeginTrans& other) :
+ SqliteQuery(other), onConflict(other.onConflict), name(other.name), transactionKw(other.transactionKw), type(other.type)
+{
+}
+
+SqliteBeginTrans::SqliteBeginTrans(SqliteBeginTrans::Type type, bool transactionKw, const QString& name)
+ : SqliteBeginTrans()
+{
+ this->type = type;
+ this->transactionKw = transactionKw;
+ this->name = name;
+}
+
+SqliteBeginTrans::SqliteBeginTrans(bool transactionKw, const QString &name, SqliteConflictAlgo onConflict)
+{
+ this->onConflict = onConflict;
+ this->transactionKw = transactionKw;
+ this->name = name;
+}
+
+SqliteStatement*SqliteBeginTrans::clone()
+{
+ return new SqliteBeginTrans(*this);
+}
+
+QString SqliteBeginTrans::typeToString(SqliteBeginTrans::Type type)
+{
+ switch (type)
+ {
+ case Type::null:
+ return QString();
+ case Type::DEFERRED:
+ return "DEFERRED";
+ case Type::IMMEDIATE:
+ return "IMMEDIATE";
+ case Type::EXCLUSIVE:
+ return "EXCLUSIVE";
+ }
+ return QString();
+}
+
+TokenList SqliteBeginTrans::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("BEGIN");
+
+ if (type != Type::null)
+ builder.withSpace().withKeyword(typeToString(type));
+
+ if (transactionKw)
+ {
+ builder.withSpace().withKeyword("TRANSACTION");
+ if (!name.isNull())
+ builder.withSpace().withOther(name, dialect);
+ }
+
+ builder.withConflict(onConflict).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.h
new file mode 100644
index 0000000..48f5b37
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitebegintrans.h
@@ -0,0 +1,38 @@
+#ifndef SQLITEBEGINTRANS_H
+#define SQLITEBEGINTRANS_H
+
+#include "sqlitequery.h"
+#include "sqliteconflictalgo.h"
+#include <QString>
+
+class API_EXPORT SqliteBeginTrans : public SqliteQuery
+{
+ public:
+ enum class Type
+ {
+ null,
+ DEFERRED,
+ IMMEDIATE,
+ EXCLUSIVE
+ };
+
+ SqliteBeginTrans();
+ SqliteBeginTrans(const SqliteBeginTrans& other);
+ SqliteBeginTrans(Type type, bool transactionKw, const QString& name);
+ SqliteBeginTrans(bool transactionKw, const QString& name, SqliteConflictAlgo onConflict);
+ SqliteStatement* clone();
+
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null; // sqlite2 only
+ QString name; // in docs sqlite2 only, but in gramma it's also sqlite3
+ bool transactionKw = false;
+ Type type = Type::null; // sqlite3 only
+
+ static QString typeToString(Type type);
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteBeginTrans> SqliteBeginTransPtr;
+
+#endif // SQLITEBEGINTRANS_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.cpp
new file mode 100644
index 0000000..cc773bb
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.cpp
@@ -0,0 +1,88 @@
+#include "sqlitecolumntype.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/utils_sql.h"
+
+SqliteColumnType::SqliteColumnType()
+{
+}
+
+SqliteColumnType::SqliteColumnType(const SqliteColumnType& other) :
+ SqliteStatement(other), name(other.name), scale(other.scale), precision(other.precision)
+{
+}
+
+SqliteColumnType::SqliteColumnType(const QString &name)
+{
+ this->name = name;
+}
+
+SqliteColumnType::SqliteColumnType(const QString &name, const QVariant& scale)
+{
+ this->name = name;
+ this->scale = scale;
+}
+
+SqliteColumnType::SqliteColumnType(const QString &name, const QVariant& scale, const QVariant& precision)
+{
+ this->name = name;
+ this->precision = precision;
+ this->scale = scale;
+}
+
+SqliteStatement* SqliteColumnType::clone()
+{
+ return new SqliteColumnType(*this);
+}
+
+bool SqliteColumnType::isPrecisionDouble()
+{
+ return !precision.isNull() && precision.toString().indexOf(".") > -1;
+}
+
+bool SqliteColumnType::isScaleDouble()
+{
+ return !scale.isNull() && scale.toString().indexOf(".") > -1;
+}
+
+TokenList SqliteColumnType::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (name.isEmpty())
+ return TokenList();
+
+ builder.withOther(name);
+
+ if (!scale.isNull())
+ {
+ builder.withSpace().withParLeft();
+ if (scale.userType() == QVariant::Int)
+ builder.withInteger(scale.toInt());
+ else if (scale.userType() == QVariant::LongLong)
+ builder.withInteger(scale.toLongLong());
+ else if (scale.userType() == QVariant::Double)
+ builder.withFloat(scale.toDouble());
+ else
+ builder.withOther(scale.toString());
+
+ if (!precision.isNull())
+ {
+ builder.withOperator(",").withSpace();
+ if (precision.userType() == QVariant::Int)
+ builder.withInteger(precision.toInt());
+ else if (precision.userType() == QVariant::LongLong)
+ builder.withInteger(precision.toLongLong());
+ else if (precision.userType() == QVariant::Double)
+ builder.withFloat(precision.toDouble());
+ else
+ builder.withOther(precision.toString());
+ }
+ builder.withParRight();
+ }
+
+ return builder.build();
+}
+
+DataType SqliteColumnType::toDataType() const
+{
+ return DataType(name, scale, precision);
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.h
new file mode 100644
index 0000000..fc87b6b
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecolumntype.h
@@ -0,0 +1,30 @@
+#ifndef SQLITECOLUMNTYPE_H
+#define SQLITECOLUMNTYPE_H
+
+#include "sqlitestatement.h"
+#include "datatype.h"
+#include <QVariant>
+
+class API_EXPORT SqliteColumnType : public SqliteStatement
+{
+ public:
+ SqliteColumnType();
+ SqliteColumnType(const SqliteColumnType& other);
+ explicit SqliteColumnType(const QString& name);
+ SqliteColumnType(const QString& name, const QVariant &scale);
+ SqliteColumnType(const QString& name, const QVariant &scale, const QVariant &precision);
+ SqliteStatement* clone();
+
+ bool isPrecisionDouble();
+ bool isScaleDouble();
+ TokenList rebuildTokensFromContents();
+ DataType toDataType() const;
+
+ QString name = QString::null;
+ QVariant scale = QVariant(); // first size number
+ QVariant precision = QVariant(); // second size number
+};
+
+typedef QSharedPointer<SqliteColumnType> SqliteColumnTypePtr;
+
+#endif // SQLITECOLUMNTYPE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.cpp
new file mode 100644
index 0000000..97be8a9
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.cpp
@@ -0,0 +1,48 @@
+#include "sqlitecommittrans.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteCommitTrans::SqliteCommitTrans()
+{
+ queryType = SqliteQueryType::CommitTrans;
+}
+
+SqliteCommitTrans::SqliteCommitTrans(bool transactionKw, const QString& name, bool endKw)
+ : SqliteCommitTrans()
+{
+ this->endKw = endKw;
+ this->transactionKw = transactionKw;
+ this->name = name;
+}
+
+SqliteCommitTrans::SqliteCommitTrans(const SqliteCommitTrans& other) :
+ SqliteQuery(other), endKw(other.endKw), name(other.name), transactionKw(other.transactionKw)
+{
+}
+
+SqliteStatement* SqliteCommitTrans::clone()
+{
+ return new SqliteCommitTrans(*this);
+}
+
+TokenList SqliteCommitTrans::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (endKw)
+ builder.withKeyword("END");
+ else
+ builder.withKeyword("COMMIT");
+
+ if (transactionKw)
+ {
+ builder.withSpace().withKeyword("TRANSACTION");
+ if (!name.isNull())
+ builder.withSpace().withOther(name, dialect);
+ }
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.h
new file mode 100644
index 0000000..ec418a6
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecommittrans.h
@@ -0,0 +1,25 @@
+#ifndef SQLITECOMMITTRANS_H
+#define SQLITECOMMITTRANS_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteCommitTrans : public SqliteQuery
+{
+ public:
+ SqliteCommitTrans();
+ SqliteCommitTrans(bool transactionKw, const QString &name, bool endKw);
+ SqliteCommitTrans(const SqliteCommitTrans& other);
+ SqliteStatement* clone();
+
+ bool endKw = false;
+ QString name = QString::null;
+ bool transactionKw = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteCommitTrans> SqliteCommitTransPtr;
+
+#endif // SQLITECOMMITTRANS_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.cpp
new file mode 100644
index 0000000..56fb42d
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.cpp
@@ -0,0 +1,37 @@
+#include "sqliteconflictalgo.h"
+
+SqliteConflictAlgo sqliteConflictAlgo(const QString& value)
+{
+ QString upper = value.toUpper();
+ if (upper == "ROLLBACK")
+ return SqliteConflictAlgo::ROLLBACK;
+ else if (upper == "ABORT")
+ return SqliteConflictAlgo::ABORT;
+ else if (upper == "FAIL")
+ return SqliteConflictAlgo::FAIL;
+ else if (upper == "IGNORE")
+ return SqliteConflictAlgo::IGNORE;
+ else if (upper == "REPLACE")
+ return SqliteConflictAlgo::REPLACE;
+ else
+ return SqliteConflictAlgo::null;
+}
+
+QString sqliteConflictAlgo(SqliteConflictAlgo value)
+{
+ switch (value)
+ {
+ case SqliteConflictAlgo::ROLLBACK:
+ return "ROLLBACK";
+ case SqliteConflictAlgo::ABORT:
+ return "ABORT";
+ case SqliteConflictAlgo::FAIL:
+ return "FAIL";
+ case SqliteConflictAlgo::IGNORE:
+ return "IGNORE";
+ case SqliteConflictAlgo::REPLACE:
+ return "REPLACE";
+ default:
+ return QString::null;
+ }
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.h
new file mode 100644
index 0000000..754672d
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteconflictalgo.h
@@ -0,0 +1,20 @@
+#ifndef SQLITECONFLICTALGO_H
+#define SQLITECONFLICTALGO_H
+
+#include "coreSQLiteStudio_global.h"
+#include <QString>
+
+enum class SqliteConflictAlgo
+{
+ ROLLBACK,
+ ABORT,
+ FAIL,
+ IGNORE,
+ REPLACE,
+ null
+};
+
+API_EXPORT SqliteConflictAlgo sqliteConflictAlgo(const QString& value);
+API_EXPORT QString sqliteConflictAlgo(SqliteConflictAlgo value);
+
+#endif // SQLITECONFLICTALGO_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.cpp
new file mode 100644
index 0000000..009f836
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.cpp
@@ -0,0 +1,92 @@
+#include "sqlitecopy.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteCopy::SqliteCopy()
+{
+ queryType = SqliteQueryType::Copy;
+}
+
+SqliteCopy::SqliteCopy(const SqliteCopy& other) :
+ SqliteQuery(other), onConflict(other.onConflict), database(other.database), table(other.table), file(other.file), delimiter(other.delimiter)
+{
+}
+
+SqliteCopy::SqliteCopy(SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QString &name3, const QString &delim)
+ : SqliteCopy()
+{
+ this->onConflict = onConflict;
+
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+
+ file = name3;
+ delimiter = delim;
+}
+
+SqliteStatement* SqliteCopy::clone()
+{
+ return new SqliteCopy(*this);
+}
+
+QStringList SqliteCopy::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteCopy::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCopy::getTableTokensInStatement()
+{
+ return getObjectTokenListFromNmDbnm();
+}
+
+TokenList SqliteCopy::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteCopy::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ FullObject fullObj = getFullObjectFromNmDbnm(FullObject::TABLE);
+ if (fullObj.isValid())
+ result << fullObj;
+
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+TokenList SqliteCopy::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("COPY").withSpace();
+ if (onConflict != SqliteConflictAlgo::null)
+ builder.withKeyword("OR").withSpace().withKeyword(sqliteConflictAlgo(onConflict)).withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withSpace();
+
+ builder.withOther(table, dialect).withSpace().withKeyword("FROM").withSpace().withString(file);
+
+ if (!delimiter.isNull())
+ builder.withSpace().withKeyword("USING").withSpace().withKeyword("DELIMITERS").withSpace().withString(delimiter);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.h
new file mode 100644
index 0000000..ff586df
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecopy.h
@@ -0,0 +1,32 @@
+#ifndef SQLITECOPY_H
+#define SQLITECOPY_H
+
+#include "sqlitequery.h"
+#include "sqliteconflictalgo.h"
+
+class API_EXPORT SqliteCopy : public SqliteQuery
+{
+ public:
+ SqliteCopy();
+ SqliteCopy(const SqliteCopy& other);
+ SqliteCopy(SqliteConflictAlgo onConflict, const QString& name1, const QString& name2, const QString& name3, const QString& delim = QString::null);
+ SqliteStatement* clone();
+
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ QString database = QString::null;
+ QString table = QString::null;
+ QString file = QString::null;
+ QString delimiter = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteCopy> SqliteCopyPtr;
+
+#endif // SQLITECOPY_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp
new file mode 100644
index 0000000..36f7aa9
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.cpp
@@ -0,0 +1,190 @@
+#include "sqlitecreateindex.h"
+#include "sqlitequerytype.h"
+#include "sqliteindexedcolumn.h"
+#include "parser/statementtokenbuilder.h"
+#include "parser/ast/sqliteexpr.h"
+#include "common/global.h"
+
+SqliteCreateIndex::SqliteCreateIndex()
+{
+ queryType = SqliteQueryType::CreateIndex;
+}
+
+SqliteCreateIndex::SqliteCreateIndex(const SqliteCreateIndex& other) :
+ SqliteQuery(other), uniqueKw(other.uniqueKw), ifNotExistsKw(other.ifNotExistsKw), database(other.database), index(other.index),
+ table(other.table)
+{
+ DEEP_COPY_COLLECTION(SqliteIndexedColumn, indexedColumns);
+}
+
+SqliteCreateIndex::SqliteCreateIndex(bool unique, bool ifNotExists, const QString &name1, const QString &name2, const QString &name3,
+ const QList<SqliteIndexedColumn *> &columns, SqliteConflictAlgo onConflict)
+ : SqliteCreateIndex()
+{
+ // Constructor for SQLite 2
+ uniqueKw = unique;
+ ifNotExistsKw = ifNotExists;
+
+ index = name1;
+
+ if (!name3.isNull())
+ {
+ database = name2;
+ table = name3;
+ }
+ else
+ table = name2;
+
+ this->onConflict = onConflict;
+ this->indexedColumns = columns;
+
+ foreach (SqliteIndexedColumn* idxCol, columns)
+ idxCol->setParent(this);
+}
+
+SqliteCreateIndex::SqliteCreateIndex(bool unique, bool ifNotExists, const QString& name1, const QString& name2, const QString& name3,
+ const QList<SqliteIndexedColumn*>& columns, SqliteExpr* where)
+ : SqliteCreateIndex()
+{
+ // Constructor for SQLite 3
+ uniqueKw = unique;
+ ifNotExistsKw = ifNotExists;
+
+ if (!name2.isNull())
+ {
+ database = name1;
+ index = name2;
+ }
+ else
+ index = name1;
+
+ table = name3;
+ this->indexedColumns = columns;
+
+ foreach (SqliteIndexedColumn* idxCol, columns)
+ idxCol->setParent(this);
+
+ this->where = where;
+}
+
+SqliteCreateIndex::~SqliteCreateIndex()
+{
+}
+
+SqliteStatement*SqliteCreateIndex::clone()
+{
+ return new SqliteCreateIndex(*this);
+}
+
+QString SqliteCreateIndex::getTargetTable() const
+{
+ return table;
+}
+
+QStringList SqliteCreateIndex::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteCreateIndex::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCreateIndex::getTableTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return getObjectTokenListFromNmDbnm("nm2", "dbnm");
+ else
+ return getTokenListFromNamedKey("nm2");
+}
+
+TokenList SqliteCreateIndex::getDatabaseTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return getDbTokenListFromNmDbnm("nm2", "dbnm");
+ else
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteCreateIndex::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj;
+ if (dialect == Dialect::Sqlite2)
+ fullObj = getFullObjectFromNmDbnm(FullObject::TABLE, "nm2", "dbnm");
+ else
+ {
+ TokenList tableTokens = getTokenListFromNamedKey("nm2");
+ if (tableTokens.size() > 0)
+ fullObj = getFullObject(FullObject::TABLE, TokenPtr(), tableTokens[0]);
+ }
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ // Index object
+ if (dialect == Dialect::Sqlite2)
+ {
+ TokenList tableTokens = getTokenListFromNamedKey("nm");
+ if (tableTokens.size() > 0)
+ fullObj = getFullObject(FullObject::INDEX, TokenPtr(), tableTokens[0]);
+ }
+ else
+ fullObj = getFullObjectFromNmDbnm(FullObject::INDEX, "nm", "dbnm");
+
+ return result;
+}
+
+TokenList SqliteCreateIndex::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("CREATE").withSpace();
+ if (uniqueKw)
+ builder.withKeyword("UNIQUE").withSpace();
+
+ builder.withKeyword("INDEX").withSpace();
+
+ if (ifNotExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (dialect == Dialect::Sqlite2)
+ {
+ builder.withOther(index, dialect).withSpace().withKeyword("ON").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect).withSpace();
+ builder.withParLeft().withStatementList(indexedColumns).withParRight();
+
+
+ if (onConflict != SqliteConflictAlgo::null)
+ builder.withSpace().withKeyword(sqliteConflictAlgo(onConflict));
+ }
+ else
+ {
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(index, dialect).withSpace().withKeyword("ON").withSpace().withOther(table, dialect).withSpace().withParLeft()
+ .withStatementList(indexedColumns).withParRight();
+ }
+
+ if (where)
+ builder.withSpace().withKeyword("WHERE").withStatement(where);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.h
new file mode 100644
index 0000000..9251b18
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateindex.h
@@ -0,0 +1,50 @@
+#ifndef SQLITECREATEINDEX_H
+#define SQLITECREATEINDEX_H
+
+#include "sqlitequery.h"
+#include "sqlitetablerelatedddl.h"
+#include "sqliteconflictalgo.h"
+#include "sqliteexpr.h"
+#include <QString>
+#include <QList>
+
+class SqliteIndexedColumn;
+
+class API_EXPORT SqliteCreateIndex : public SqliteQuery, public SqliteTableRelatedDdl
+{
+ public:
+ SqliteCreateIndex();
+ SqliteCreateIndex(const SqliteCreateIndex& other);
+ SqliteCreateIndex(bool unique, bool ifNotExists, const QString& name1, const QString& name2,
+ const QString& name3, const QList<SqliteIndexedColumn*>& columns,
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null);
+ SqliteCreateIndex(bool unique, bool ifNotExists, const QString& name1, const QString& name2,
+ const QString& name3, const QList<SqliteIndexedColumn*>& columns,
+ SqliteExpr* where);
+ ~SqliteCreateIndex();
+ SqliteStatement* clone();
+
+ QString getTargetTable() const;
+
+ bool uniqueKw = false;
+ bool ifNotExistsKw = false;
+ QList<SqliteIndexedColumn*> indexedColumns;
+ // The database refers to index name in Sqlite3, but in Sqlite2 it refers to the table.
+ QString database = QString::null;
+ QString index = QString::null;
+ QString table = QString::null;
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ SqliteExpr* where = nullptr;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteCreateIndex> SqliteCreateIndexPtr;
+
+#endif // SQLITECREATEINDEX_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp
new file mode 100644
index 0000000..e31e512
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.cpp
@@ -0,0 +1,771 @@
+#include "sqlitecreatetable.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/utils_sql.h"
+#include "common/global.h"
+
+SqliteCreateTable::SqliteCreateTable()
+{
+ queryType = SqliteQueryType::CreateTable;
+}
+
+SqliteCreateTable::SqliteCreateTable(const SqliteCreateTable& other) :
+ SqliteQuery(other), ifNotExistsKw(other.ifNotExistsKw), tempKw(other.tempKw), temporaryKw(other.temporaryKw),
+ database(other.database), table(other.table), withOutRowId(other.withOutRowId)
+{
+ DEEP_COPY_COLLECTION(Column, columns);
+ DEEP_COPY_COLLECTION(Constraint, constraints);
+ DEEP_COPY_FIELD(SqliteSelect, select);
+}
+
+SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString &name1, const QString &name2, const QList<Column *> &columns, const QList<Constraint*>& constraints)
+ : SqliteCreateTable()
+{
+ init(ifNotExistsKw, temp, name1, name2);
+ this->columns = columns;
+ foreach (Column* column, columns)
+ column->setParent(this);
+
+ SqliteCreateTable::Constraint* constr = nullptr;
+ foreach (constr, constraints)
+ {
+ if (this->constraints.size() > 0 &&
+ this->constraints.last()->type == SqliteCreateTable::Constraint::NAME_ONLY)
+ {
+ constr->name = this->constraints.last()->name;
+ delete this->constraints.takeLast();
+ }
+ this->constraints << constr;
+ constr->setParent(this);
+ }
+}
+
+SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString& name1, const QString& name2, const QList<SqliteCreateTable::Column*>& columns, const QList<SqliteCreateTable::Constraint*>& constraints, const QString& withOutRowId) :
+ SqliteCreateTable(ifNotExistsKw, temp, name1, name2, columns, constraints)
+{
+ this->withOutRowId = withOutRowId;
+}
+
+SqliteCreateTable::SqliteCreateTable(bool ifNotExistsKw, int temp, const QString &name1, const QString &name2, SqliteSelect *select)
+ : SqliteCreateTable()
+{
+ init(ifNotExistsKw, temp, name1, name2);
+ this->select = select;
+ if (select)
+ select->setParent(this);
+}
+
+SqliteCreateTable::~SqliteCreateTable()
+{
+}
+
+SqliteStatement*SqliteCreateTable::clone()
+{
+ return new SqliteCreateTable(*this);
+}
+
+QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getConstraints(SqliteCreateTable::Constraint::Type type) const
+{
+ QList<SqliteCreateTable::Constraint*> results;
+ foreach (Constraint* constr, constraints)
+ if (constr->type == type)
+ results << constr;
+
+ return results;
+}
+
+SqliteStatement* SqliteCreateTable::getPrimaryKey() const
+{
+ foreach (Constraint* constr, getConstraints(Constraint::PRIMARY_KEY))
+ return constr;
+
+ Column::Constraint* colConstr = nullptr;
+ foreach (Column* col, columns)
+ {
+ colConstr = col->getConstraint(Column::Constraint::PRIMARY_KEY);
+ if (colConstr)
+ return colConstr;
+ }
+
+ return nullptr;
+}
+
+QStringList SqliteCreateTable::getPrimaryKeyColumns() const
+{
+ QStringList colNames;
+ SqliteStatement* primaryKey = getPrimaryKey();
+ if (!primaryKey)
+ return colNames;
+
+ SqliteCreateTable::Column::Constraint* columnConstr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(primaryKey);
+ if (columnConstr)
+ {
+ colNames << dynamic_cast<SqliteCreateTable::Column*>(columnConstr->parentStatement())->name;
+ return colNames;
+ }
+
+ SqliteCreateTable::Constraint* tableConstr = dynamic_cast<SqliteCreateTable::Constraint*>(primaryKey);
+ if (tableConstr)
+ {
+ foreach (SqliteIndexedColumn* idxCol, tableConstr->indexedColumns)
+ colNames << idxCol->name;
+ }
+ return colNames;
+}
+
+SqliteCreateTable::Column* SqliteCreateTable::getColumn(const QString& colName)
+{
+ foreach (Column* col, columns)
+ {
+ if (col->name.compare(colName, Qt::CaseInsensitive) == 0)
+ return col;
+ }
+ return nullptr;
+}
+
+QList<SqliteCreateTable::Constraint*> SqliteCreateTable::getForeignKeysByTable(const QString& foreignTable) const
+{
+ QList<Constraint*> results;
+ foreach (Constraint* constr, constraints)
+ if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0)
+ results << constr;
+
+ return results;
+}
+
+QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::getColumnForeignKeysByTable(const QString& foreignTable) const
+{
+ QList<Column::Constraint*> results;
+ foreach (Column* col, columns)
+ results += col->getForeignKeysByTable(foreignTable);
+
+ return results;
+}
+
+QStringList SqliteCreateTable::getColumnNames() const
+{
+ QStringList names;
+ foreach (Column* col, columns)
+ names << col->name;
+
+ return names;
+}
+
+QHash<QString, QString> SqliteCreateTable::getModifiedColumnsMap(bool lowercaseKeys, Qt::CaseSensitivity cs) const
+{
+ QHash<QString, QString> colMap;
+ QString key;
+ foreach (Column* col, columns)
+ {
+ key = lowercaseKeys ? col->originalName.toLower() : col->originalName;
+ if (col->name.compare(col->originalName, cs) != 0)
+ colMap[key] = col->name;
+ }
+
+ return colMap;
+}
+
+QStringList SqliteCreateTable::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteCreateTable::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCreateTable::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteCreateTable::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteCreateTable::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+TokenList SqliteCreateTable::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("CREATE");
+ if (tempKw)
+ builder.withSpace().withKeyword("TEMP");
+ else if (temporaryKw)
+ builder.withSpace().withKeyword("TEMPORARY");
+
+ builder.withSpace().withKeyword("TABLE");
+ if (ifNotExistsKw)
+ builder.withSpace().withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS");
+
+ builder.withSpace();
+ if (dialect == Dialect::Sqlite3 && !database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect);
+
+ if (select)
+ builder.withSpace().withKeyword("AS").withSpace().withStatement(select);
+ else
+ {
+ builder.withSpace().withParLeft().withStatementList(columns);
+ if (constraints.size() > 0)
+ builder.withOperator(",").withStatementList(constraints);
+
+ builder.withParRight();
+
+ if (!withOutRowId.isNull())
+ builder.withSpace().withKeyword("WITHOUT").withSpace().withOther("ROWID");
+ }
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
+
+void SqliteCreateTable::init(bool ifNotExistsKw, int temp, const QString &name1, const QString &name2)
+{
+ this->ifNotExistsKw = ifNotExistsKw;
+ if (temp == 2)
+ temporaryKw = true;
+ else if (temp == 1)
+ tempKw = true;
+
+ if (name2.isNull())
+ table = name1;
+ else
+ {
+ database = name1;
+ table = name2;
+ }
+}
+
+
+SqliteCreateTable::Column::Constraint::Constraint()
+{
+}
+
+SqliteCreateTable::Column::Constraint::Constraint(const SqliteCreateTable::Column::Constraint& other) :
+ SqliteStatement(other), type(other.type), name(other.name), sortOrder(other.sortOrder), onConflict(other.onConflict),
+ autoincrKw(other.autoincrKw), literalValue(other.literalValue), literalNull(other.literalNull), ctime(other.ctime), id(other.id),
+ collationName(other.collationName), deferrable(other.deferrable), initially(other.initially)
+{
+ DEEP_COPY_FIELD(SqliteExpr, expr);
+ DEEP_COPY_FIELD(SqliteForeignKey, foreignKey);
+}
+
+SqliteCreateTable::Column::Constraint::~Constraint()
+{
+}
+
+SqliteStatement* SqliteCreateTable::Column::Constraint::clone()
+{
+ return new SqliteCreateTable::Column::Constraint(*this);
+}
+
+void SqliteCreateTable::Column::Constraint::initDefNameOnly(const QString &name)
+{
+ this->type = SqliteCreateTable::Column::Constraint::NAME_ONLY;
+ this->name = name;
+}
+
+void SqliteCreateTable::Column::Constraint::initDefId(const QString &id)
+{
+ this->type = SqliteCreateTable::Column::Constraint::DEFAULT;
+ this->id = id;
+}
+
+void SqliteCreateTable::Column::Constraint::initDefTerm(const QVariant &value, bool minus)
+{
+ this->type = SqliteCreateTable::Column::Constraint::DEFAULT;
+ if (minus)
+ {
+ if (value.type() == QVariant::Double)
+ literalValue = -(value.toDouble());
+ else if (value.type() == QVariant::LongLong)
+ literalValue = -(value.toLongLong());
+ }
+ else if (value.isNull())
+ {
+ literalValue = value;
+ literalNull = true;
+ }
+ else
+ literalValue = value;
+}
+
+void SqliteCreateTable::Column::Constraint::initDefCTime(const QString &name)
+{
+ this->type = SqliteCreateTable::Column::Constraint::DEFAULT;
+ ctime = name;
+}
+
+void SqliteCreateTable::Column::Constraint::initDefExpr(SqliteExpr *expr)
+{
+ this->type = SqliteCreateTable::Column::Constraint::DEFAULT;
+ this->expr = expr;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteCreateTable::Column::Constraint::initNull(SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Column::Constraint::NULL_;
+ onConflict = algo;
+}
+
+void SqliteCreateTable::Column::Constraint::initNotNull(SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Column::Constraint::NOT_NULL;
+ onConflict = algo;
+}
+
+void SqliteCreateTable::Column::Constraint::initPk(SqliteSortOrder order, SqliteConflictAlgo algo, bool autoincr)
+{
+ this->type = SqliteCreateTable::Column::Constraint::PRIMARY_KEY;
+ sortOrder = order;
+ onConflict = algo;
+ autoincrKw = autoincr;
+}
+
+void SqliteCreateTable::Column::Constraint::initUnique(SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Column::Constraint::UNIQUE;
+ onConflict = algo;
+}
+
+void SqliteCreateTable::Column::Constraint::initCheck()
+{
+ this->type = SqliteCreateTable::Column::Constraint::CHECK;
+}
+
+void SqliteCreateTable::Column::Constraint::initCheck(SqliteExpr *expr)
+{
+ this->type = SqliteCreateTable::Column::Constraint::CHECK;
+ this->expr = expr;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteCreateTable::Column::Constraint::initCheck(SqliteExpr *expr, SqliteConflictAlgo algo)
+{
+ initCheck(expr);
+ this->onConflict = algo;
+}
+
+void SqliteCreateTable::Column::Constraint::initFk(const QString& table, const QList<SqliteIndexedColumn*>& indexedColumns, const QList<SqliteForeignKey::Condition*>& conditions)
+{
+ this->type = SqliteCreateTable::Column::Constraint::FOREIGN_KEY;
+
+ SqliteForeignKey* fk = new SqliteForeignKey();
+ fk->foreignTable = table;
+ fk->indexedColumns = indexedColumns;
+ fk->conditions = conditions;
+ foreignKey = fk;
+ fk->setParent(this);
+
+ foreach (SqliteIndexedColumn* idxCol, indexedColumns)
+ idxCol->setParent(fk);
+
+ foreach (SqliteForeignKey::Condition* cond, conditions)
+ cond->setParent(fk);
+}
+
+void SqliteCreateTable::Column::Constraint::initDefer(SqliteInitially initially, SqliteDeferrable deferrable)
+{
+ this->type = SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY;
+ this->deferrable = deferrable;
+ this->initially = initially;
+}
+
+void SqliteCreateTable::Column::Constraint::initColl(const QString &name)
+{
+ this->type = SqliteCreateTable::Column::Constraint::COLLATE;
+ this->collationName = name;
+}
+
+QString SqliteCreateTable::Column::Constraint::typeString() const
+{
+ switch (type)
+ {
+ case SqliteCreateTable::Column::Constraint::PRIMARY_KEY:
+ return "PRIMARY KEY";
+ case SqliteCreateTable::Column::Constraint::NOT_NULL:
+ return "NOT NULL";
+ case SqliteCreateTable::Column::Constraint::UNIQUE:
+ return "UNIQUE";
+ case SqliteCreateTable::Column::Constraint::CHECK:
+ return "CHECK";
+ case SqliteCreateTable::Column::Constraint::DEFAULT:
+ return "DEFAULT";
+ case SqliteCreateTable::Column::Constraint::COLLATE:
+ return "COLLATE";
+ case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
+ return "FOREIGN KEY";
+ case SqliteCreateTable::Column::Constraint::NULL_:
+ case SqliteCreateTable::Column::Constraint::NAME_ONLY:
+ case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteCreateTable::Constraint::Constraint()
+{
+}
+
+SqliteCreateTable::Constraint::Constraint(const SqliteCreateTable::Constraint& other) :
+ SqliteStatement(other), type(other.type), name(other.name), autoincrKw(other.autoincrKw), onConflict(other.onConflict),
+ afterComma(other.afterComma)
+{
+ DEEP_COPY_FIELD(SqliteForeignKey, foreignKey);
+ DEEP_COPY_FIELD(SqliteExpr, expr);
+ DEEP_COPY_COLLECTION(SqliteIndexedColumn, indexedColumns);
+}
+
+SqliteCreateTable::Constraint::~Constraint()
+{
+}
+
+SqliteStatement*SqliteCreateTable::Constraint::clone()
+{
+ return new SqliteCreateTable::Constraint(*this);
+}
+
+void SqliteCreateTable::Constraint::initNameOnly(const QString &name)
+{
+ this->type = SqliteCreateTable::Constraint::NAME_ONLY;
+ this->name = name;
+}
+
+void SqliteCreateTable::Constraint::initPk(const QList<SqliteIndexedColumn *> &indexedColumns, bool autoincr, SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Constraint::PRIMARY_KEY;
+ this->indexedColumns = indexedColumns;
+ autoincrKw = autoincr;
+ onConflict = algo;
+
+ foreach (SqliteIndexedColumn* idxCol, indexedColumns)
+ idxCol->setParent(this);
+}
+
+void SqliteCreateTable::Constraint::initUnique(const QList<SqliteIndexedColumn *> &indexedColumns, SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Constraint::UNIQUE;
+ this->indexedColumns = indexedColumns;
+ onConflict = algo;
+
+ foreach (SqliteIndexedColumn* idxCol, indexedColumns)
+ idxCol->setParent(this);
+}
+
+void SqliteCreateTable::Constraint::initCheck(SqliteExpr *expr, SqliteConflictAlgo algo)
+{
+ this->type = SqliteCreateTable::Constraint::CHECK;
+ this->expr = expr;
+ onConflict = algo;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteCreateTable::Constraint::initCheck()
+{
+ this->type = SqliteCreateTable::Constraint::CHECK;
+}
+
+void SqliteCreateTable::Constraint::initFk(const QList<SqliteIndexedColumn *> &indexedColumns, const QString& table, const QList<SqliteIndexedColumn *> &fkColumns, const QList<SqliteForeignKey::Condition *> &conditions, SqliteInitially initially, SqliteDeferrable deferrable)
+{
+ this->type = SqliteCreateTable::Constraint::FOREIGN_KEY;
+ this->indexedColumns = indexedColumns;
+
+ foreach (SqliteIndexedColumn* idxCol, indexedColumns)
+ idxCol->setParent(this);
+
+ SqliteForeignKey* fk = new SqliteForeignKey();
+ fk->foreignTable = table;
+ fk->indexedColumns = fkColumns;
+ fk->conditions = conditions;
+ fk->deferrable = deferrable;
+ fk->initially = initially;
+
+ fk->setParent(this);
+
+ foreach (SqliteIndexedColumn* idxCol, fkColumns)
+ idxCol->setParent(fk);
+
+ foreach (SqliteForeignKey::Condition* cond, conditions)
+ cond->setParent(fk);
+
+ this->foreignKey = fk;
+}
+
+bool SqliteCreateTable::Constraint::doesAffectColumn(const QString& columnName)
+{
+ return getAffectedColumnIdx(columnName) > -1;
+}
+
+int SqliteCreateTable::Constraint::getAffectedColumnIdx(const QString& columnName)
+{
+ int i = 0;
+ foreach (SqliteIndexedColumn* idxCol, indexedColumns)
+ {
+ if (idxCol->name.compare(columnName, Qt::CaseInsensitive) == 0)
+ return i;
+
+ i++;
+ }
+
+ return -1;
+}
+
+QString SqliteCreateTable::Constraint::typeString() const
+{
+ switch (type)
+ {
+ case SqliteCreateTable::Constraint::PRIMARY_KEY:
+ return "PRIMARY KEY";
+ case SqliteCreateTable::Constraint::UNIQUE:
+ return "UNIQUE";
+ case SqliteCreateTable::Constraint::CHECK:
+ return "CHECK";
+ case SqliteCreateTable::Constraint::FOREIGN_KEY:
+ return "FOREIGN KEY";
+ case SqliteCreateTable::Constraint::NAME_ONLY:
+ return QString::null;
+ }
+ return QString::null;
+}
+
+TokenList SqliteCreateTable::Constraint::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (!name.isNull())
+ builder.withKeyword("CONSTRAINT").withSpace().withOther(name, dialect).withSpace();
+
+ switch (type)
+ {
+ case SqliteCreateTable::Constraint::PRIMARY_KEY:
+ {
+ builder.withKeyword("PRIMARY").withSpace().withKeyword("KEY").withSpace().withParLeft().withStatementList(indexedColumns).withParRight();
+
+ if (autoincrKw)
+ builder.withSpace().withKeyword("AUTOINCREMENT");
+
+ builder.withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Constraint::UNIQUE:
+ {
+ builder.withKeyword("UNIQUE").withSpace().withParLeft().withStatementList(indexedColumns).withParRight().withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Constraint::CHECK:
+ {
+ builder.withKeyword("CHECK").withSpace().withParLeft().withStatement(expr).withParRight().withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Constraint::FOREIGN_KEY:
+ {
+ builder.withKeyword("FOREIGN").withSpace().withKeyword("KEY").withSpace().withParLeft().withStatementList(indexedColumns)
+ .withParRight().withStatement(foreignKey);
+ break;
+ }
+ case SqliteCreateTable::Constraint::NAME_ONLY:
+ break;
+ }
+
+ return builder.build();
+}
+
+SqliteCreateTable::Column::Column()
+{
+}
+
+SqliteCreateTable::Column::Column(const SqliteCreateTable::Column& other) :
+ SqliteStatement(other), name(other.name), originalName(other.originalName)
+{
+ DEEP_COPY_FIELD(SqliteColumnType, type);
+ DEEP_COPY_COLLECTION(Constraint, constraints);
+}
+
+SqliteCreateTable::Column::Column(const QString &name, SqliteColumnType *type, const QList<Constraint *> &constraints)
+{
+ this->name = name;
+ this->originalName = name;
+ this->type = type;
+
+ if (type)
+ type->setParent(this);
+
+ SqliteCreateTable::Column::Constraint* constr = nullptr;
+ foreach (constr, constraints)
+ {
+ // If last constraint on list is NAME_ONLY we apply the name
+ // to current constraint and remove NAME_ONLY.
+ // Exception is DEFERRABLE_ONLY.
+ if (this->constraints.size() > 0 &&
+ this->constraints.last()->type == SqliteCreateTable::Column::Constraint::NAME_ONLY &&
+ constr->type != SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY)
+ {
+ constr->name = this->constraints.last()->name;
+ delete this->constraints.takeLast();
+ }
+
+ // And the opposite of above. Now we apply DEFERRABLE_ONLY,
+ // but only if last item in the list is not NAME_ONLY.
+ if (constr->type == SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY &&
+ this->constraints.size() > 0 &&
+ this->constraints.last()->type != SqliteCreateTable::Column::Constraint::NAME_ONLY)
+ {
+ SqliteCreateTable::Column::Constraint* last = this->constraints.last();
+ last->deferrable = constr->deferrable;
+ last->initially = constr->initially;
+ delete constr;
+
+ // We don't want deleted constr to be added to list. We finish this now.
+ continue;
+ }
+
+ this->constraints << constr;
+ constr->setParent(this);
+ }
+}
+
+SqliteCreateTable::Column::~Column()
+{
+}
+
+SqliteStatement*SqliteCreateTable::Column::clone()
+{
+ return new SqliteCreateTable::Column(*this);
+}
+
+bool SqliteCreateTable::Column::hasConstraint(SqliteCreateTable::Column::Constraint::Type type) const
+{
+ return getConstraint(type) != nullptr;
+}
+
+SqliteCreateTable::Column::Constraint* SqliteCreateTable::Column::getConstraint(SqliteCreateTable::Column::Constraint::Type type) const
+{
+ foreach (Constraint* constr, constraints)
+ if (constr->type == type)
+ return constr;
+
+ return nullptr;
+}
+
+QList<SqliteCreateTable::Column::Constraint*> SqliteCreateTable::Column::getForeignKeysByTable(const QString& foreignTable) const
+{
+ QList<Constraint*> results;
+ foreach (Constraint* constr, constraints)
+ if (constr->type == Constraint::FOREIGN_KEY && constr->foreignKey->foreignTable.compare(foreignTable, Qt::CaseInsensitive) == 0)
+ results << constr;
+
+ return results;
+}
+
+QStringList SqliteCreateTable::Column::getColumnsInStatement()
+{
+ return getStrListFromValue(name);
+}
+
+TokenList SqliteCreateTable::Column::getColumnTokensInStatement()
+{
+ return getTokenListFromNamedKey("columnid");
+}
+
+TokenList SqliteCreateTable::Column::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withOther(name, dialect).withStatement(type).withStatementList(constraints, "");
+ return builder.build();
+}
+
+TokenList SqliteCreateTable::Column::Constraint::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (!name.isNull())
+ builder.withKeyword("CONSTRAINT").withSpace().withOther(name, dialect).withSpace();
+
+ switch (type)
+ {
+ case SqliteCreateTable::Column::Constraint::PRIMARY_KEY:
+ {
+ builder.withKeyword("PRIMARY").withSpace().withKeyword("KEY").withSortOrder(sortOrder).withConflict(onConflict);
+ if (autoincrKw)
+ builder.withSpace().withKeyword("AUTOINCREMENT");
+
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::NOT_NULL:
+ {
+ builder.withKeyword("NOT").withSpace().withKeyword("NULL").withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::UNIQUE:
+ {
+ builder.withKeyword("UNIQUE").withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::CHECK:
+ {
+ builder.withKeyword("CHECK").withSpace().withParLeft().withStatement(expr).withParRight().withConflict(onConflict);
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::DEFAULT:
+ {
+ builder.withKeyword("DEFAULT").withSpace();
+ if (!id.isNull())
+ builder.withOther(id);
+ else if (!ctime.isNull())
+ builder.withKeyword(ctime.toUpper());
+ else if (expr)
+ builder.withParLeft().withStatement(expr).withParRight();
+ else if (literalNull)
+ builder.withKeyword("NULL");
+ else
+ builder.withLiteralValue(literalValue);
+
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::COLLATE:
+ {
+ builder.withKeyword("COLLATE").withSpace().withOther(collationName, dialect);
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
+ {
+ builder.withStatement(foreignKey);
+ break;
+ }
+ case SqliteCreateTable::Column::Constraint::NULL_:
+ case SqliteCreateTable::Column::Constraint::NAME_ONLY:
+ case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
+ break;
+ }
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h
new file mode 100644
index 0000000..f3be244
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetable.h
@@ -0,0 +1,205 @@
+#ifndef SQLITECREATETABLE_H
+#define SQLITECREATETABLE_H
+
+#include "sqlitequery.h"
+#include "sqliteconflictalgo.h"
+#include "sqliteexpr.h"
+#include "sqliteforeignkey.h"
+#include "sqliteindexedcolumn.h"
+#include "sqliteselect.h"
+#include "sqlitecolumntype.h"
+#include "sqlitesortorder.h"
+#include "sqlitedeferrable.h"
+#include <QVariant>
+#include <QList>
+
+class API_EXPORT SqliteCreateTable : public SqliteQuery
+{
+ public:
+ class API_EXPORT Column : public SqliteStatement
+ {
+ public:
+ class API_EXPORT Constraint : public SqliteStatement
+ {
+ public:
+ enum Type
+ {
+ PRIMARY_KEY,
+ NOT_NULL,
+ UNIQUE,
+ CHECK,
+ DEFAULT,
+ COLLATE,
+ FOREIGN_KEY,
+ NULL_, // not officially supported
+ NAME_ONLY, // unofficial, because of bizarre sqlite grammar
+ DEFERRABLE_ONLY // unofficial, because of bizarre sqlite grammar
+ };
+
+ Constraint();
+ Constraint(const Constraint& other);
+ ~Constraint();
+ SqliteStatement* clone();
+
+ void initDefNameOnly(const QString& name);
+ void initDefId(const QString& id);
+ void initDefTerm(const QVariant& value, bool minus = false);
+ void initDefCTime(const QString& name);
+ void initDefExpr(SqliteExpr* expr);
+ void initNull(SqliteConflictAlgo algo);
+ void initNotNull(SqliteConflictAlgo algo);
+ void initPk(SqliteSortOrder order, SqliteConflictAlgo algo, bool autoincr);
+ void initUnique(SqliteConflictAlgo algo);
+ void initCheck();
+ void initCheck(SqliteExpr* expr);
+ void initCheck(SqliteExpr* expr, SqliteConflictAlgo algo);
+ void initFk(const QString& table, const QList<SqliteIndexedColumn*>& indexedColumns, const QList<SqliteForeignKey::Condition*>& conditions);
+ void initDefer(SqliteInitially initially, SqliteDeferrable deferrable);
+ void initColl(const QString& name);
+ QString typeString() const;
+
+ Type type;
+ QString name = QString::null;
+ SqliteSortOrder sortOrder = SqliteSortOrder::null;
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ bool autoincrKw = false;
+ SqliteExpr* expr = nullptr;
+ QVariant literalValue;
+ bool literalNull = false;
+ QString ctime;
+ QString id;
+ QString collationName = QString::null;
+ SqliteForeignKey* foreignKey = nullptr;
+ SqliteDeferrable deferrable = SqliteDeferrable::null;
+ SqliteInitially initially = SqliteInitially::null;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ typedef QSharedPointer<Constraint> ConstraintPtr;
+
+ Column();
+ Column(const Column& other);
+ Column(const QString& name, SqliteColumnType* type,
+ const QList<Constraint*>& constraints);
+ ~Column();
+ SqliteStatement* clone();
+
+ bool hasConstraint(Constraint::Type type) const;
+ Constraint* getConstraint(Constraint::Type type) const;
+ QList<Constraint*> getForeignKeysByTable(const QString& foreignTable) const;
+
+ QString name = QString::null;
+ SqliteColumnType* type = nullptr;
+ QList<Constraint*> constraints;
+
+ /**
+ * @brief originalName
+ * Used to remember original name when column was edited and the name was changed.
+ * It's defined in the constructor to the same value as the name member.
+ */
+ QString originalName = QString::null;
+
+ protected:
+ QStringList getColumnsInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList rebuildTokensFromContents();
+ };
+
+ typedef QSharedPointer<Column> ColumnPtr;
+
+ class API_EXPORT Constraint : public SqliteStatement
+ {
+ public:
+ enum Type
+ {
+ PRIMARY_KEY,
+ UNIQUE,
+ CHECK,
+ FOREIGN_KEY,
+ NAME_ONLY // unofficial, because of bizarre sqlite grammar
+ };
+
+ Constraint();
+ Constraint(const Constraint& other);
+ ~Constraint();
+ SqliteStatement* clone();
+
+ void initNameOnly(const QString& name);
+ void initPk(const QList<SqliteIndexedColumn*>& indexedColumns,
+ bool autoincr, SqliteConflictAlgo algo);
+ void initUnique(const QList<SqliteIndexedColumn*>& indexedColumns,
+ SqliteConflictAlgo algo);
+ void initCheck(SqliteExpr* expr, SqliteConflictAlgo algo);
+ void initCheck();
+ void initFk(const QList<SqliteIndexedColumn*>& indexedColumns, const QString& table,
+ const QList<SqliteIndexedColumn*>& fkColumns, const QList<SqliteForeignKey::Condition*>& conditions,
+ SqliteInitially initially, SqliteDeferrable deferrable);
+
+ bool doesAffectColumn(const QString& columnName);
+ int getAffectedColumnIdx(const QString& columnName);
+ QString typeString() const;
+
+ Type type;
+ QString name = QString::null;
+ bool autoincrKw = false; // not in docs, but needs to be supported
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ SqliteForeignKey* foreignKey = nullptr;
+ SqliteExpr* expr = nullptr;
+ QList<SqliteIndexedColumn*> indexedColumns;
+ bool afterComma = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ typedef QSharedPointer<Constraint> ConstraintPtr;
+
+ SqliteCreateTable();
+ SqliteCreateTable(const SqliteCreateTable& other);
+ SqliteCreateTable(bool ifNotExistsKw, int temp, const QString& name1, const QString& name2,
+ const QList<Column*>& columns, const QList<Constraint*>& constraints);
+ SqliteCreateTable(bool ifNotExistsKw, int temp, const QString& name1, const QString& name2,
+ const QList<Column*>& columns, const QList<Constraint*>& constraints,
+ const QString& withOutRowId);
+ SqliteCreateTable(bool ifNotExistsKw, int temp, const QString& name1, const QString& name2,
+ SqliteSelect* select);
+ ~SqliteCreateTable();
+ SqliteStatement* clone();
+
+ QList<Constraint*> getConstraints(Constraint::Type type) const;
+ SqliteStatement* getPrimaryKey() const;
+ QStringList getPrimaryKeyColumns() const;
+ Column* getColumn(const QString& colName);
+ QList<Constraint*> getForeignKeysByTable(const QString& foreignTable) const;
+ QList<Column::Constraint*> getColumnForeignKeysByTable(const QString& foreignTable) const;
+ QStringList getColumnNames() const;
+ QHash<QString,QString> getModifiedColumnsMap(bool lowercaseKeys = false, Qt::CaseSensitivity cs = Qt::CaseInsensitive) const;
+
+ bool ifNotExistsKw = false;
+ bool tempKw = false;
+ bool temporaryKw = false;
+ QString database = QString::null;
+ QString table = QString::null;
+ QList<Column*> columns;
+ QList<Constraint*> constraints;
+ SqliteSelect* select = nullptr;
+ QString withOutRowId = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void init(bool ifNotExistsKw, int temp, const QString& name1, const QString& name2);
+
+};
+
+typedef QSharedPointer<SqliteCreateTable> SqliteCreateTablePtr;
+
+#endif // SQLITECREATETABLE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp
new file mode 100644
index 0000000..3b7b0ea
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.cpp
@@ -0,0 +1,381 @@
+#include "sqlitecreatetrigger.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "sqlitedelete.h"
+#include "sqliteinsert.h"
+#include "sqliteupdate.h"
+#include "sqliteselect.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+
+SqliteCreateTrigger::SqliteCreateTrigger()
+{
+ queryType = SqliteQueryType::CreateTrigger;
+}
+
+SqliteCreateTrigger::SqliteCreateTrigger(const SqliteCreateTrigger& other) :
+ SqliteQuery(other), tempKw(other.tempKw), temporaryKw(other.temporaryKw), ifNotExistsKw(other.ifNotExistsKw), database(other.database),
+ trigger(other.trigger), table(other.table), eventTime(other.eventTime), scope(other.scope)
+{
+ DEEP_COPY_FIELD(Event, event);
+ DEEP_COPY_FIELD(SqliteExpr, precondition);
+
+ // Special case of deep collection copy
+ SqliteQuery* newQuery = nullptr;
+ foreach (SqliteQuery* query, other.queries)
+ {
+ switch (query->queryType)
+ {
+ case SqliteQueryType::Delete:
+ newQuery = new SqliteDelete(*dynamic_cast<SqliteDelete*>(query));
+ break;
+ case SqliteQueryType::Insert:
+ newQuery = new SqliteInsert(*dynamic_cast<SqliteInsert*>(query));
+ break;
+ case SqliteQueryType::Update:
+ newQuery = new SqliteUpdate(*dynamic_cast<SqliteUpdate*>(query));
+ break;
+ case SqliteQueryType::Select:
+ newQuery = new SqliteSelect(*dynamic_cast<SqliteSelect*>(query));
+ break;
+ default:
+ newQuery = nullptr;
+ break;
+ }
+
+ if (!newQuery)
+ continue;
+
+ newQuery->setParent(this);
+ queries << newQuery;
+ }
+}
+
+SqliteCreateTrigger::SqliteCreateTrigger(int temp, bool ifNotExists, const QString &name1, const QString &name2, const QString &name3, Time time, SqliteCreateTrigger::Event *event, Scope foreachType, SqliteExpr *when, const QList<SqliteQuery *> &queries, int sqliteVersion) :
+ SqliteCreateTrigger()
+{
+ this->ifNotExistsKw = ifNotExists;
+ this->scope = foreachType;
+ if (temp == 2)
+ temporaryKw = true;
+ else if (temp == 1)
+ tempKw = true;
+
+ if (sqliteVersion == 3)
+ {
+ if (name2.isNull())
+ trigger = name1;
+ else
+ {
+ database = name1;
+ trigger = name2;
+ }
+ table = name3;
+ }
+ else
+ {
+ trigger = name1;
+ if (name3.isNull())
+ table = name2;
+ else
+ {
+ database = name2;
+ table = name3;
+ }
+ }
+
+ this->event = event;
+ eventTime = time;
+ this->precondition = when;
+ this->queries = queries;
+
+ if (event)
+ event->setParent(this);
+
+ if (when)
+ when->setParent(this);
+
+ foreach (SqliteQuery* q, queries)
+ q->setParent(this);
+}
+
+SqliteCreateTrigger::~SqliteCreateTrigger()
+{
+}
+
+SqliteStatement*SqliteCreateTrigger::clone()
+{
+ return new SqliteCreateTrigger(*this);
+}
+
+QString SqliteCreateTrigger::getTargetTable() const
+{
+ return table;
+}
+
+QString SqliteCreateTrigger::time(SqliteCreateTrigger::Time eventTime)
+{
+ switch (eventTime)
+ {
+ case SqliteCreateTrigger::Time::BEFORE:
+ return "BEFORE";
+ case SqliteCreateTrigger::Time::AFTER:
+ return "AFTER";
+ case SqliteCreateTrigger::Time::INSTEAD_OF:
+ return "INSTEAD OF";
+ case SqliteCreateTrigger::Time::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteCreateTrigger::Time SqliteCreateTrigger::time(const QString& eventTime)
+{
+ if (eventTime == "BEFORE")
+ return Time::BEFORE;
+
+ if (eventTime == "AFTER")
+ return Time::AFTER;
+
+ if (eventTime == "INSTEAD OF")
+ return Time::INSTEAD_OF;
+
+ return Time::null;
+}
+
+QString SqliteCreateTrigger::scopeToString(SqliteCreateTrigger::Scope scope)
+{
+ switch (scope)
+ {
+ case SqliteCreateTrigger::Scope::FOR_EACH_ROW:
+ return "FOR EACH ROW";
+ case SqliteCreateTrigger::Scope::FOR_EACH_STATEMENT:
+ return "FOR EACH STATEMENT";
+ case SqliteCreateTrigger::Scope::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteCreateTrigger::Scope SqliteCreateTrigger::stringToScope(const QString& scope)
+{
+ if (scope == "FOR EACH ROW")
+ return Scope::FOR_EACH_ROW;
+
+ if (scope == "FOR EACH STATEMENT")
+ return Scope::FOR_EACH_STATEMENT;
+
+ return Scope::null;
+}
+
+QStringList SqliteCreateTrigger::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteCreateTrigger::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCreateTrigger::getTableTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return getObjectTokenListFromNmDbnm("nm2", "dbnm");
+ else
+ return getTokenListFromNamedKey("nm2");
+}
+
+TokenList SqliteCreateTrigger::getDatabaseTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return getDbTokenListFromNmDbnm("nm2", "dbnm");
+ else
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteCreateTrigger::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj;
+ if (dialect == Dialect::Sqlite2)
+ fullObj = getFullObjectFromNmDbnm(FullObject::TABLE, "nm2", "dbnm");
+ else
+ {
+ TokenList tableTokens = getTokenListFromNamedKey("nm2");
+ if (tableTokens.size() > 0)
+ fullObj = getFullObject(FullObject::TABLE, TokenPtr(), tableTokens[0]);
+ }
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ // Trigger object
+ if (dialect == Dialect::Sqlite2)
+ {
+ TokenList tableTokens = getTokenListFromNamedKey("nm");
+ if (tableTokens.size() > 0)
+ fullObj = getFullObject(FullObject::TRIGGER, TokenPtr(), tableTokens[0]);
+ }
+ else
+ fullObj = getFullObjectFromNmDbnm(FullObject::TRIGGER, "nm", "dbnm");
+
+ return result;
+}
+
+SqliteCreateTrigger::Event::Event()
+{
+ this->type = Event::null;
+}
+
+SqliteCreateTrigger::Event::Event(SqliteCreateTrigger::Event::Type type)
+{
+ this->type = type;
+}
+
+SqliteCreateTrigger::Event::Event(const SqliteCreateTrigger::Event& other) :
+ SqliteStatement(other), type(other.type), columnNames(other.columnNames)
+{
+}
+
+SqliteCreateTrigger::Event::Event(const QList<QString> &columns)
+{
+ this->type = UPDATE_OF;
+ columnNames = columns;
+}
+
+SqliteStatement*SqliteCreateTrigger::Event::clone()
+{
+ return new SqliteCreateTrigger::Event(*this);
+}
+
+TokenList SqliteCreateTrigger::Event::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ switch (type)
+ {
+ case SqliteCreateTrigger::Event::INSERT:
+ builder.withKeyword("INSERT");
+ break;
+ case SqliteCreateTrigger::Event::UPDATE:
+ builder.withKeyword("UPDATE");
+ break;
+ case SqliteCreateTrigger::Event::DELETE:
+ builder.withKeyword("DELETE");
+ break;
+ case SqliteCreateTrigger::Event::UPDATE_OF:
+ builder.withKeyword("UPDATE").withSpace().withKeyword("OF").withSpace().withOtherList(columnNames);
+ break;
+ case SqliteCreateTrigger::Event::null:
+ break;
+ }
+
+ return builder.build();
+}
+
+QString SqliteCreateTrigger::Event::typeToString(SqliteCreateTrigger::Event::Type type)
+{
+ switch (type)
+ {
+ case SqliteCreateTrigger::Event::INSERT:
+ return "INSERT";
+ case SqliteCreateTrigger::Event::UPDATE:
+ return "UPDATE";
+ case SqliteCreateTrigger::Event::DELETE:
+ return "DELETE";
+ case SqliteCreateTrigger::Event::UPDATE_OF:
+ return "UPDATE OF";
+ case SqliteCreateTrigger::Event::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteCreateTrigger::Event::Type SqliteCreateTrigger::Event::stringToType(const QString& type)
+{
+ if (type == "INSERT")
+ return INSERT;
+
+ if (type == "UPDATE")
+ return UPDATE;
+
+ if (type == "DELETE")
+ return DELETE;
+
+ if (type == "UPDATE OF")
+ return UPDATE_OF;
+
+ return Event::null;
+}
+
+TokenList SqliteCreateTrigger::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("CREATE").withSpace();
+ if (tempKw)
+ builder.withKeyword("TEMP").withSpace();
+ else if (temporaryKw)
+ builder.withKeyword("TEMPORARY").withSpace();
+
+ builder.withKeyword("TRIGGER").withSpace();
+ if (ifNotExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (dialect == Dialect::Sqlite3 && !database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(trigger, dialect).withSpace();
+ switch (eventTime)
+ {
+ case Time::BEFORE:
+ builder.withKeyword("BEFORE").withSpace();
+ break;
+ case Time::AFTER:
+ builder.withKeyword("AFTER").withSpace();
+ break;
+ case Time::INSTEAD_OF:
+ builder.withKeyword("INSTEAD").withSpace().withKeyword("OF").withSpace();
+ break;
+ case Time::null:
+ break;
+ }
+
+ builder.withStatement(event).withSpace().withKeyword("ON").withSpace();
+ if (dialect == Dialect::Sqlite2 && !database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect).withSpace();
+
+ switch (scope)
+ {
+ case SqliteCreateTrigger::Scope::FOR_EACH_ROW:
+ builder.withKeyword("FOR").withSpace().withKeyword("EACH").withSpace().withKeyword("ROW").withSpace();
+ break;
+ case SqliteCreateTrigger::Scope::FOR_EACH_STATEMENT:
+ builder.withKeyword("FOR").withSpace().withKeyword("EACH").withSpace().withKeyword("STATEMENT").withSpace();
+ break;
+ case SqliteCreateTrigger::Scope::null:
+ break;
+ }
+
+ if (precondition)
+ builder.withKeyword("WHEN").withStatement(precondition).withSpace();
+
+ builder.withKeyword("BEGIN").withSpace().withStatementList(queries, ";").withOperator(";").withSpace().withKeyword("END");
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.h
new file mode 100644
index 0000000..2fb8ae4
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatetrigger.h
@@ -0,0 +1,96 @@
+#ifndef SQLITECREATETRIGGER_H
+#define SQLITECREATETRIGGER_H
+
+#include "sqlitequery.h"
+#include "sqlitetablerelatedddl.h"
+
+#include <QString>
+#include <QList>
+
+class SqliteExpr;
+
+class API_EXPORT SqliteCreateTrigger : public SqliteQuery, public SqliteTableRelatedDdl
+{
+ public:
+ enum class Time
+ {
+ BEFORE,
+ AFTER,
+ INSTEAD_OF,
+ null
+ };
+
+ class API_EXPORT Event : public SqliteStatement
+ {
+ public:
+ enum Type
+ {
+ INSERT,
+ UPDATE,
+ DELETE,
+ UPDATE_OF,
+ null
+ };
+
+ Event();
+ explicit Event(Type type);
+ Event(const Event& other);
+ explicit Event(const QList<QString>& columns);
+ SqliteStatement* clone();
+
+ TokenList rebuildTokensFromContents();
+
+ static QString typeToString(Type type);
+ static Type stringToType(const QString& type);
+
+ Type type;
+ QStringList columnNames;
+ };
+
+ enum class Scope
+ {
+ FOR_EACH_ROW,
+ FOR_EACH_STATEMENT, // Sqlite2 only
+ null
+ };
+
+ SqliteCreateTrigger();
+ SqliteCreateTrigger(const SqliteCreateTrigger& other);
+ SqliteCreateTrigger(int temp, bool ifNotExists, const QString& name1, const QString& name2,
+ const QString& name3, Time time, Event* event, Scope scope,
+ SqliteExpr* precondition, const QList<SqliteQuery*>& queries, int sqliteVersion);
+ ~SqliteCreateTrigger();
+ SqliteStatement* clone();
+
+ QString getTargetTable() const;
+
+ bool tempKw = false;
+ bool temporaryKw = false;
+ bool ifNotExistsKw = false;
+ // The database refers to the trigger name in Sqlite3, but in Sqlite2 it refers to the table.
+ QString database = QString::null;
+ QString trigger = QString::null;
+ QString table = QString::null; // can also be a view name
+ Event* event = nullptr;
+ Time eventTime = Time::null;
+ Scope scope = Scope::null;
+ SqliteExpr* precondition = nullptr;
+ QList<SqliteQuery*> queries;
+
+ static QString time(Time eventTime);
+ static Time time(const QString& eventTime);
+ static QString scopeToString(Scope scope);
+ static Scope stringToScope(const QString& scope);
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteCreateTrigger> SqliteCreateTriggerPtr;
+
+#endif // SQLITECREATETRIGGER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp
new file mode 100644
index 0000000..6b11c3c
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.cpp
@@ -0,0 +1,120 @@
+#include "sqlitecreateview.h"
+#include "sqliteselect.h"
+#include "sqlitequerytype.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+
+SqliteCreateView::SqliteCreateView()
+{
+ queryType = SqliteQueryType::CreateView;
+}
+
+SqliteCreateView::SqliteCreateView(const SqliteCreateView& other) :
+ SqliteQuery(other), tempKw(other.tempKw), temporaryKw(other.temporaryKw), ifNotExists(other.ifNotExists),
+ database(other.database), view(other.view)
+{
+ DEEP_COPY_FIELD(SqliteSelect, select);
+
+}
+
+SqliteCreateView::SqliteCreateView(int temp, bool ifNotExists, const QString &name1, const QString &name2, SqliteSelect *select) :
+ SqliteCreateView()
+{
+ this->ifNotExists = ifNotExists;
+
+ if (name2.isNull())
+ view = name1;
+ else
+ {
+ database = name1;
+ view = name2;
+ }
+
+ if (temp == 2)
+ temporaryKw = true;
+ else if (temp == 1)
+ tempKw = true;
+
+ this->select = select;
+
+ if (select)
+ select->setParent(this);
+}
+
+SqliteCreateView::~SqliteCreateView()
+{
+}
+
+SqliteStatement*SqliteCreateView::clone()
+{
+ return new SqliteCreateView(*this);
+}
+
+QStringList SqliteCreateView::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCreateView::getDatabaseTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite3)
+ return getDbTokenListFromFullname();
+ else
+ return TokenList();
+}
+
+QList<SqliteStatement::FullObject> SqliteCreateView::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // View object
+ FullObject fullObj;
+ if (dialect == Dialect::Sqlite3)
+ fullObj = getFullObjectFromFullname(FullObject::VIEW);
+ else
+ {
+ TokenList tokens = getTokenListFromNamedKey("nm");
+ if (tokens.size() > 0)
+ fullObj = getFullObject(FullObject::VIEW, TokenPtr(), tokens[0]);
+ }
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ if (dialect == Dialect::Sqlite3)
+ {
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+ }
+
+ return result;
+}
+
+TokenList SqliteCreateView::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("CREATE").withSpace();
+ if (tempKw)
+ builder.withKeyword("TEMP").withSpace();
+ else if (temporaryKw)
+ builder.withKeyword("TEMPORARY").withSpace();
+
+ builder.withKeyword("VIEW").withSpace();
+ if (ifNotExists)
+ builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (dialect == Dialect::Sqlite3 && !database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(view, dialect).withSpace().withKeyword("AS").withStatement(select);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h
new file mode 100644
index 0000000..4858227
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreateview.h
@@ -0,0 +1,35 @@
+#ifndef SQLITECREATEVIEW_H
+#define SQLITECREATEVIEW_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class SqliteSelect;
+
+class API_EXPORT SqliteCreateView : public SqliteQuery
+{
+ public:
+ SqliteCreateView();
+ SqliteCreateView(const SqliteCreateView& other);
+ SqliteCreateView(int temp, bool ifNotExists, const QString& name1, const QString& name2, SqliteSelect* select);
+ ~SqliteCreateView();
+
+ SqliteStatement* clone();
+
+ bool tempKw = false;
+ bool temporaryKw = false;
+ bool ifNotExists = false;
+ QString database = QString::null;
+ QString view = QString::null;
+ SqliteSelect* select = nullptr;
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteCreateView> SqliteCreateViewPtr;
+
+#endif // SQLITECREATEVIEW_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.cpp
new file mode 100644
index 0000000..bc38dc9
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.cpp
@@ -0,0 +1,120 @@
+#include "sqlitecreatevirtualtable.h"
+#include "sqlitequerytype.h"
+
+#include <parser/lexer.h>
+#include <parser/statementtokenbuilder.h>
+
+SqliteCreateVirtualTable::SqliteCreateVirtualTable()
+{
+ queryType = SqliteQueryType::CreateVirtualTable;
+}
+
+SqliteCreateVirtualTable::SqliteCreateVirtualTable(const SqliteCreateVirtualTable& other) :
+ SqliteQuery(other), ifNotExistsKw(other.ifNotExistsKw), database(other.database), table(other.table), module(other.module), args(other.args)
+{
+}
+
+SqliteCreateVirtualTable::SqliteCreateVirtualTable(bool ifNotExists, const QString &name1, const QString &name2, const QString &name3) :
+ SqliteCreateVirtualTable()
+{
+ initName(name1, name2);
+ this->ifNotExistsKw = ifNotExists;
+ module = name3;
+}
+
+SqliteCreateVirtualTable::SqliteCreateVirtualTable(bool ifNotExists, const QString &name1, const QString &name2, const QString &name3, const QList<QString> &args) :
+ SqliteCreateVirtualTable()
+{
+ initName(name1, name2);
+ this->ifNotExistsKw = ifNotExists;
+ module = name3;
+ this->args = args;
+}
+
+SqliteStatement*SqliteCreateVirtualTable::clone()
+{
+ return new SqliteCreateVirtualTable(*this);
+}
+
+QStringList SqliteCreateVirtualTable::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteCreateVirtualTable::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteCreateVirtualTable::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteCreateVirtualTable::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteCreateVirtualTable::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+void SqliteCreateVirtualTable::initName(const QString &name1, const QString &name2)
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+TokenList SqliteCreateVirtualTable::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("CREATE").withSpace().withKeyword("VIRTUAL").withSpace().withKeyword("TABLE");
+ if (ifNotExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withKeyword("USING").withSpace().withOther(module, dialect);
+ if (!args.isEmpty())
+ {
+ builder.withSpace();
+ int i = 0;
+ for (const QString& arg : args)
+ {
+ if (i > 0)
+ builder.withOperator(",").withSpace();
+
+ builder.withTokens(Lexer::tokenize(arg, Dialect::Sqlite3));
+ i++;
+ }
+ }
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.h
new file mode 100644
index 0000000..cb2d231
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitecreatevirtualtable.h
@@ -0,0 +1,42 @@
+#ifndef SQLITECREATEVIRTUALTABLE_H
+#define SQLITECREATEVIRTUALTABLE_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+#include <QList>
+
+class API_EXPORT SqliteCreateVirtualTable : public SqliteQuery
+{
+ public:
+ SqliteCreateVirtualTable();
+ SqliteCreateVirtualTable(const SqliteCreateVirtualTable& other);
+ SqliteCreateVirtualTable(bool ifNotExists, const QString& name1, const QString& name2,
+ const QString& name3);
+ SqliteCreateVirtualTable(bool ifNotExists, const QString& name1, const QString& name2,
+ const QString& name3, const QList<QString>& args);
+
+ SqliteStatement* clone();
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void initName(const QString& name1, const QString& name2);
+
+ public:
+ bool ifNotExistsKw = false;
+ QString database = QString::null;
+ QString table = QString::null;
+ QString module = QString::null;
+ QList<QString> args;
+};
+
+typedef QSharedPointer<SqliteCreateVirtualTable> SqliteCreateVirtualTablePtr;
+
+#endif // SQLITECREATEVIRTUALTABLE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.cpp
new file mode 100644
index 0000000..4ef4d51
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.cpp
@@ -0,0 +1,54 @@
+#include "sqlitedeferrable.h"
+
+QString sqliteDeferrable(SqliteDeferrable deferrable)
+{
+ switch (deferrable)
+ {
+ case SqliteDeferrable::NOT_DEFERRABLE:
+ return "NOT DEFERRABLE";
+ case SqliteDeferrable::DEFERRABLE:
+ return "DEFERRABLE";
+ case SqliteDeferrable::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteDeferrable sqliteDeferrable(const QString& deferrable)
+{
+ QString upper = deferrable.toUpper();
+ if (upper == "NOT DEFERRABLE")
+ return SqliteDeferrable::NOT_DEFERRABLE;
+
+ if (upper == "DEFERRABLE")
+ return SqliteDeferrable::DEFERRABLE;
+
+ return SqliteDeferrable::null;
+}
+
+
+QString sqliteInitially(SqliteInitially initially)
+{
+ switch (initially)
+ {
+ case SqliteInitially::DEFERRED:
+ return "DEFERRED";
+ case SqliteInitially::IMMEDIATE:
+ return "IMMEDIATE";
+ case SqliteInitially::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteInitially sqliteInitially(const QString& initially)
+{
+ QString upper = initially.toUpper();
+ if (upper == "DEFERRED")
+ return SqliteInitially::DEFERRED;
+
+ if (upper == "IMMEDIATE")
+ return SqliteInitially::IMMEDIATE;
+
+ return SqliteInitially::null;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.h
new file mode 100644
index 0000000..8fdf06a
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedeferrable.h
@@ -0,0 +1,27 @@
+#ifndef SQLITEDEFERRABLE_H
+#define SQLITEDEFERRABLE_H
+
+#include "coreSQLiteStudio_global.h"
+#include <QString>
+
+enum class SqliteDeferrable
+{
+ null,
+ NOT_DEFERRABLE,
+ DEFERRABLE
+};
+
+enum class SqliteInitially
+{
+ null,
+ DEFERRED,
+ IMMEDIATE
+};
+
+API_EXPORT QString sqliteDeferrable(SqliteDeferrable deferrable);
+API_EXPORT SqliteDeferrable sqliteDeferrable(const QString& deferrable);
+
+API_EXPORT QString sqliteInitially(SqliteInitially initially);
+API_EXPORT SqliteInitially sqliteInitially(const QString& initially);
+
+#endif // SQLITEDEFERRABLE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.cpp
new file mode 100644
index 0000000..60e5878
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.cpp
@@ -0,0 +1,137 @@
+#include "sqlitedelete.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+#include "sqlitewith.h"
+
+SqliteDelete::SqliteDelete()
+{
+ queryType = SqliteQueryType::Delete;
+}
+
+SqliteDelete::SqliteDelete(const SqliteDelete& other) :
+ SqliteQuery(other), database(other.database), table(other.table), indexedByKw(other.indexedByKw), notIndexedKw(other.notIndexedKw),
+ indexedBy(other.indexedBy)
+{
+ DEEP_COPY_FIELD(SqliteExpr, where);
+ DEEP_COPY_FIELD(SqliteWith, with);
+}
+
+SqliteDelete::SqliteDelete(const QString &name1, const QString &name2, const QString& indexedByName, SqliteExpr *where, SqliteWith* with)
+ : SqliteDelete()
+{
+ init(name1, name2, where, with);
+ this->indexedBy = indexedByName;
+ this->indexedByKw = true;
+}
+
+SqliteDelete::SqliteDelete(const QString &name1, const QString &name2, bool notIndexedKw, SqliteExpr *where, SqliteWith* with)
+ : SqliteDelete()
+{
+ init(name1, name2, where, with);
+ this->notIndexedKw = notIndexedKw;
+}
+
+SqliteDelete::~SqliteDelete()
+{
+}
+
+SqliteStatement*SqliteDelete::clone()
+{
+ return new SqliteDelete(*this);
+}
+
+QStringList SqliteDelete::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteDelete::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteDelete::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteDelete::getDatabaseTokensInStatement()
+{
+ if (tokensMap.contains("fullname"))
+ return getDbTokenListFromFullname();
+
+ if (tokensMap.contains("nm"))
+ return extractPrintableTokens(tokensMap["nm"]);
+
+ return TokenList();
+}
+
+QList<SqliteStatement::FullObject> SqliteDelete::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+ if (!tokensMap.contains("fullname"))
+ return result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+void SqliteDelete::init(const QString &name1, const QString &name2, SqliteExpr *where, SqliteWith* with)
+{
+ this->where = where;
+ if (where)
+ where->setParent(this);
+
+ this->with = with;
+ if (with)
+ with->setParent(this);
+
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+TokenList SqliteDelete::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (with)
+ builder.withStatement(with);
+
+ builder.withKeyword("DELETE").withSpace().withKeyword("FROM").withSpace();
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect);
+
+ if (indexedByKw)
+ builder.withSpace().withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect);
+ else if (notIndexedKw)
+ builder.withSpace().withKeyword("NOT").withSpace().withKeyword("INDEXED");
+
+ if (where)
+ builder.withSpace().withKeyword("WHERE").withStatement(where);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.h
new file mode 100644
index 0000000..90e1385
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedelete.h
@@ -0,0 +1,45 @@
+#ifndef SQLITEDELETE_H
+#define SQLITEDELETE_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+
+class SqliteExpr;
+class SqliteWith;
+
+class API_EXPORT SqliteDelete : public SqliteQuery
+{
+ public:
+ SqliteDelete();
+ SqliteDelete(const SqliteDelete& other);
+ SqliteDelete(const QString& name1, const QString& name2, const QString& indexedByName, SqliteExpr* where, SqliteWith* with);
+ SqliteDelete(const QString& name1, const QString& name2, bool notIndexedKw, SqliteExpr* where, SqliteWith* with);
+ ~SqliteDelete();
+
+ SqliteStatement* clone();
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void init(const QString& name1, const QString& name2, SqliteExpr* where, SqliteWith* with);
+
+ public:
+ QString database = QString::null;
+ QString table = QString::null;
+ bool indexedByKw = false;
+ bool notIndexedKw = false;
+ QString indexedBy = QString::null;
+ SqliteExpr* where = nullptr;
+ SqliteWith* with = nullptr;
+};
+
+typedef QSharedPointer<SqliteDelete> SqliteDeletePtr;
+
+#endif // SQLITEDELETE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.cpp
new file mode 100644
index 0000000..1f874d3
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.cpp
@@ -0,0 +1,48 @@
+#include "sqlitedetach.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "common/global.h"
+#include "parser/statementtokenbuilder.h"
+
+SqliteDetach::SqliteDetach()
+{
+ queryType = SqliteQueryType::Detach;
+}
+
+SqliteDetach::SqliteDetach(const SqliteDetach& other) :
+ SqliteQuery(other), databaseKw(other.databaseKw)
+{
+ DEEP_COPY_FIELD(SqliteExpr, name);
+}
+
+SqliteDetach::SqliteDetach(bool databaseKw, SqliteExpr *name)
+ :SqliteDetach()
+{
+ this->databaseKw = databaseKw;
+ this->name = name;
+ if (name)
+ name->setParent(this);
+}
+
+SqliteDetach::~SqliteDetach()
+{
+}
+
+SqliteStatement*SqliteDetach::clone()
+{
+ return new SqliteDetach(*this);
+}
+
+TokenList SqliteDetach::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("DETACH").withSpace();
+
+ if (databaseKw)
+ builder.withKeyword("DATABASE").withSpace();
+
+ builder.withStatement(name).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.h
new file mode 100644
index 0000000..725cd47
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedetach.h
@@ -0,0 +1,27 @@
+#ifndef SQLITEDETACH_H
+#define SQLITEDETACH_H
+
+#include "sqlitequery.h"
+
+class SqliteExpr;
+
+class API_EXPORT SqliteDetach : public SqliteQuery
+{
+ public:
+ SqliteDetach();
+ SqliteDetach(const SqliteDetach& other);
+ SqliteDetach(bool databaseKw, SqliteExpr* name);
+ ~SqliteDetach();
+
+ SqliteStatement* clone();
+
+ bool databaseKw = false;
+ SqliteExpr* name = nullptr;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteDetach> SqliteDetachPtr;
+
+#endif // SQLITEDETACH_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.cpp
new file mode 100644
index 0000000..df924fe
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.cpp
@@ -0,0 +1,78 @@
+#include "sqlitedropindex.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteDropIndex::SqliteDropIndex()
+{
+ queryType = SqliteQueryType::DropIndex;
+}
+
+SqliteDropIndex::SqliteDropIndex(const SqliteDropIndex& other) :
+ SqliteQuery(other), ifExistsKw(other.ifExistsKw), database(other.database), index(other.index)
+{
+}
+
+SqliteDropIndex::SqliteDropIndex(bool ifExists, const QString &name1, const QString &name2)
+ : SqliteDropIndex()
+{
+ this->ifExistsKw = ifExists;
+ if (!name2.isNull())
+ {
+ database = name1;
+ index = name2;
+ }
+ else
+ index = name1;
+}
+
+SqliteStatement*SqliteDropIndex::clone()
+{
+ return new SqliteDropIndex(*this);
+}
+
+QStringList SqliteDropIndex::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteDropIndex::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteDropIndex::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Index object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::INDEX);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+
+TokenList SqliteDropIndex::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("DROP").withSpace().withKeyword("INDEX").withSpace();
+
+ if (ifExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(index).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.h
new file mode 100644
index 0000000..9ce7065
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropindex.h
@@ -0,0 +1,29 @@
+#ifndef SQLITEDROPINDEX_H
+#define SQLITEDROPINDEX_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteDropIndex : public SqliteQuery
+{
+ public:
+ SqliteDropIndex();
+ SqliteDropIndex(const SqliteDropIndex& other);
+ SqliteDropIndex(bool ifExistsKw, const QString& name1, const QString& name2);
+
+ SqliteStatement* clone();
+
+ bool ifExistsKw = false;
+ QString database = QString::null;
+ QString index = QString::null;
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteDropIndex> SqliteDropIndexPtr;
+
+#endif // SQLITEDROPINDEX_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.cpp
new file mode 100644
index 0000000..9c4aa37
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.cpp
@@ -0,0 +1,86 @@
+#include "sqlitedroptable.h"
+#include "sqlitequerytype.h"
+#include <parser/statementtokenbuilder.h>
+
+SqliteDropTable::SqliteDropTable()
+{
+ queryType = SqliteQueryType::DropTable;
+}
+
+SqliteDropTable::SqliteDropTable(const SqliteDropTable& other) :
+ SqliteQuery(other), ifExistsKw(other.ifExistsKw), database(other.database), table(other.table)
+{
+}
+
+SqliteDropTable::SqliteDropTable(bool ifExists, const QString& name1, const QString& name2)
+ : SqliteDropTable()
+{
+ this->ifExistsKw = ifExists;
+ if (name2.isNull())
+ this->table = name1;
+ else
+ {
+ this->database = name1;
+ this->table = name2;
+ }
+}
+
+SqliteStatement* SqliteDropTable::clone()
+{
+ return new SqliteDropTable(*this);
+}
+
+QStringList SqliteDropTable::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteDropTable::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteDropTable::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteDropTable::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteDropTable::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+TokenList SqliteDropTable::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("DROP").withSpace().withKeyword("TABLE").withSpace();
+
+ if (ifExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.h
new file mode 100644
index 0000000..edc4da4
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptable.h
@@ -0,0 +1,31 @@
+#ifndef SQLITEDROPTABLE_H
+#define SQLITEDROPTABLE_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteDropTable : public SqliteQuery
+{
+ public:
+ SqliteDropTable();
+ SqliteDropTable(const SqliteDropTable& other);
+ SqliteDropTable(bool ifExistsKw, const QString& name1, const QString& name2);
+
+ SqliteStatement* clone();
+
+ bool ifExistsKw = false;
+ QString database = QString::null;
+ QString table = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteDropTable> SqliteDropTablePtr;
+
+#endif // SQLITEDROPTABLE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.cpp
new file mode 100644
index 0000000..471d558
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.cpp
@@ -0,0 +1,79 @@
+#include "sqlitedroptrigger.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteDropTrigger::SqliteDropTrigger()
+{
+ queryType = SqliteQueryType::DropTrigger;
+}
+
+SqliteDropTrigger::SqliteDropTrigger(const SqliteDropTrigger& other) :
+ SqliteQuery(other), ifExistsKw(other.ifExistsKw), database(other.database), trigger(other.trigger)
+{
+}
+
+SqliteDropTrigger::SqliteDropTrigger(bool ifExists, const QString &name1, const QString &name2)
+ : SqliteDropTrigger()
+{
+ this->ifExistsKw = ifExists;
+
+ if (name2.isNull())
+ trigger = name1;
+ else
+ {
+ database = name1;
+ trigger = name2;
+ }
+}
+
+SqliteStatement*SqliteDropTrigger::clone()
+{
+ return new SqliteDropTrigger(*this);
+}
+
+QStringList SqliteDropTrigger::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteDropTrigger::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteDropTrigger::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TRIGGER);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+
+TokenList SqliteDropTrigger::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("DROP").withSpace().withKeyword("TRIGGER").withSpace();
+
+ if (ifExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(trigger).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.h
new file mode 100644
index 0000000..5221959
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedroptrigger.h
@@ -0,0 +1,29 @@
+#ifndef SQLITEDROPTRIGGER_H
+#define SQLITEDROPTRIGGER_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteDropTrigger : public SqliteQuery
+{
+ public:
+ SqliteDropTrigger();
+ SqliteDropTrigger(const SqliteDropTrigger& other);
+ SqliteDropTrigger(bool ifExistsKw, const QString& name1, const QString& name2);
+
+ SqliteStatement* clone();
+
+ bool ifExistsKw = false;
+ QString database = QString::null;
+ QString trigger = QString::null;
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteDropTrigger> SqliteDropTriggerPtr;
+
+#endif // SQLITEDROPTRIGGER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.cpp
new file mode 100644
index 0000000..06d70db
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.cpp
@@ -0,0 +1,85 @@
+#include "sqlitedropview.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteDropView::SqliteDropView()
+{
+ queryType = SqliteQueryType::DropView;
+}
+
+SqliteDropView::SqliteDropView(const SqliteDropView& other) :
+ SqliteQuery(other), ifExistsKw(other.ifExistsKw), database(other.database), view(other.view)
+{
+}
+
+SqliteDropView::SqliteDropView(bool ifExists, const QString &name1, const QString &name2)
+ : SqliteDropView()
+{
+ this->ifExistsKw = ifExists;
+
+ if (name2.isNull())
+ view = name1;
+ else
+ {
+ database = name1;
+ view = name2;
+ }
+}
+
+SqliteStatement*SqliteDropView::clone()
+{
+ return new SqliteDropView(*this);
+}
+
+QStringList SqliteDropView::getDatabasesInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return QStringList();
+
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteDropView::getDatabaseTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2)
+ return TokenList();
+
+ return getDbTokenListFromFullname();
+}
+
+QList<SqliteStatement::FullObject> SqliteDropView::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::VIEW);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+
+TokenList SqliteDropView::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("DROP").withSpace().withKeyword("VIEW").withSpace();
+
+ if (ifExistsKw)
+ builder.withKeyword("IF").withSpace().withKeyword("EXISTS").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(view).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.h
new file mode 100644
index 0000000..853ccef
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitedropview.h
@@ -0,0 +1,29 @@
+#ifndef SQLITEDROPVIEW_H
+#define SQLITEDROPVIEW_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteDropView : public SqliteQuery
+{
+ public:
+ SqliteDropView();
+ SqliteDropView(const SqliteDropView& other);
+ SqliteDropView(bool ifExistsKw, const QString& name1, const QString& name2);
+
+ SqliteStatement* clone();
+
+ bool ifExistsKw = false;
+ QString database = QString::null;
+ QString view = QString::null;
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteDropView> SqliteDropViewPtr;
+
+#endif // SQLITEDROPVIEW_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.cpp
new file mode 100644
index 0000000..628aea5
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.cpp
@@ -0,0 +1,27 @@
+#include "sqliteemptyquery.h"
+#include "sqlitequerytype.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/unused.h"
+
+SqliteEmptyQuery::SqliteEmptyQuery()
+{
+ queryType = SqliteQueryType::EMPTY;
+}
+
+SqliteEmptyQuery::SqliteEmptyQuery(const SqliteEmptyQuery& other) :
+ SqliteEmptyQuery()
+{
+ UNUSED(other);
+}
+
+SqliteStatement*SqliteEmptyQuery::clone()
+{
+ return new SqliteEmptyQuery(*this);
+}
+
+TokenList SqliteEmptyQuery::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withOperator(";");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.h
new file mode 100644
index 0000000..3380532
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteemptyquery.h
@@ -0,0 +1,19 @@
+#ifndef SQLITEEMPTYQUERY_H
+#define SQLITEEMPTYQUERY_H
+
+#include "sqlitequery.h"
+
+class API_EXPORT SqliteEmptyQuery : public SqliteQuery
+{
+ public:
+ SqliteEmptyQuery();
+ SqliteEmptyQuery(const SqliteEmptyQuery& other);
+
+ SqliteStatement* clone();
+
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteEmptyQuery> SqliteEmptyQueryPtr;
+
+#endif // SQLITEEMPTYQUERY_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp
new file mode 100644
index 0000000..969f029
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.cpp
@@ -0,0 +1,644 @@
+#include "sqliteexpr.h"
+#include "sqliteraise.h"
+#include "sqliteselect.h"
+#include "sqlitecolumntype.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/utils_sql.h"
+#include "common/global.h"
+#include <QDebug>
+
+SqliteExpr::SqliteExpr()
+{
+}
+
+SqliteExpr::SqliteExpr(const SqliteExpr& other) :
+ SqliteStatement(other),
+ mode(other.mode), literalValue(other.literalValue), literalNull(other.literalNull), bindParam(other.bindParam), database(other.database), table(other.table),
+ column(other.column), unaryOp(other.unaryOp), binaryOp(other.binaryOp), function(other.function), collation(other.collation),
+ ctime(other.ctime), distinctKw(other.distinctKw), allKw(other.allKw), star(other.star), notKw(other.notKw), like(other.like),
+ notNull(other.notNull), possibleDoubleQuotedString(other.possibleDoubleQuotedString)
+{
+ DEEP_COPY_FIELD(SqliteColumnType, columnType);
+ DEEP_COPY_FIELD(SqliteExpr, expr1);
+ DEEP_COPY_FIELD(SqliteExpr, expr2);
+ DEEP_COPY_FIELD(SqliteExpr, expr3);
+ DEEP_COPY_COLLECTION(SqliteExpr, exprList);
+ DEEP_COPY_FIELD(SqliteSelect, select);
+ DEEP_COPY_FIELD(SqliteRaise, raiseFunction);
+}
+
+SqliteExpr::~SqliteExpr()
+{
+}
+
+SqliteExpr::LikeOp SqliteExpr::likeOp(const QString &value)
+{
+ QString upper = value.toUpper();
+ if (upper == "LIKE")
+ return SqliteExpr::LikeOp::LIKE;
+ else if (upper == "GLOB")
+ return SqliteExpr::LikeOp::GLOB;
+ else if (upper == "REGEXP")
+ return SqliteExpr::LikeOp::REGEXP;
+ else if (upper == "MATCH")
+ return SqliteExpr::LikeOp::MATCH;
+ else
+ return SqliteExpr::LikeOp::null;
+}
+
+QString SqliteExpr::likeOp(SqliteExpr::LikeOp value)
+{
+ switch (value)
+ {
+ case SqliteExpr::LikeOp::LIKE:
+ return "LIKE";
+ case SqliteExpr::LikeOp::GLOB:
+ return "GLOB";
+ case SqliteExpr::LikeOp::REGEXP:
+ return "REGEXP";
+ case SqliteExpr::LikeOp::MATCH:
+ return "MATCH";
+ default:
+ return QString::null;
+ }
+}
+
+SqliteExpr::NotNull SqliteExpr::notNullOp(const QString &value)
+{
+ if (value == "ISNULL")
+ return SqliteExpr::NotNull::ISNULL;
+ else if (value == "NOTNULL")
+ return SqliteExpr::NotNull::NOTNULL;
+ else if (value == "NOT NULL")
+ return SqliteExpr::NotNull::NOT_NULL;
+ else
+ return SqliteExpr::NotNull::null;
+}
+
+QString SqliteExpr::notNullOp(SqliteExpr::NotNull value)
+{
+ switch (value)
+ {
+ case SqliteExpr::NotNull::ISNULL:
+ return "ISNULL";
+ case SqliteExpr::NotNull::NOT_NULL:
+ return "NOT NULL";
+ case SqliteExpr::NotNull::NOTNULL:
+ return "NOTNULL";
+ default:
+ return QString::null;
+ }
+}
+
+SqliteStatement*SqliteExpr::clone()
+{
+ return new SqliteExpr(*this);
+}
+
+void SqliteExpr::initLiteral(const QVariant &value)
+{
+ mode = SqliteExpr::Mode::LITERAL_VALUE;
+ if (value.isNull())
+ initNull();
+
+ literalValue = value;
+}
+
+void SqliteExpr::initNull()
+{
+ literalNull = true;
+}
+
+void SqliteExpr::initCTime(const QString &name)
+{
+ mode = SqliteExpr::Mode::CTIME;
+ ctime = name;
+}
+
+void SqliteExpr::initSubExpr(SqliteExpr *expr)
+{
+ mode = SqliteExpr::Mode::SUB_EXPR;
+ expr1 = expr;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initBindParam(const QString& value)
+{
+ mode = SqliteExpr::Mode::BIND_PARAM;
+ bindParam = value;
+}
+
+void SqliteExpr::initCollate(SqliteExpr *expr, const QString& value)
+{
+ mode = SqliteExpr::Mode::COLLATE;
+ expr1 = expr;
+ collation = value;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initCast(SqliteExpr *expr, SqliteColumnType *type)
+{
+ mode = SqliteExpr::Mode::CAST;
+ expr1 = expr;
+ columnType = type;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initFunction(const QString& fnName, int distinct, const QList<SqliteExpr*>& exprList)
+{
+ mode = SqliteExpr::Mode::FUNCTION;
+ function = fnName;
+ this->exprList = exprList;
+ if (distinct == 1)
+ distinctKw = true;
+ else if (distinct == 2)
+ allKw = true;
+
+ foreach (SqliteExpr* expr, exprList)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initFunction(const QString& fnName, bool star)
+{
+ mode = SqliteExpr::Mode::FUNCTION;
+ function = fnName;
+ this->star = star;
+}
+
+void SqliteExpr::initBinOp(SqliteExpr *expr1, const QString& op, SqliteExpr *expr2)
+{
+ mode = SqliteExpr::Mode::BINARY_OP;
+ this->expr1 = expr1;
+ this->expr2 = expr2;
+ binaryOp = op;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+}
+
+void SqliteExpr::initUnaryOp(SqliteExpr *expr, const QString& op)
+{
+ mode = SqliteExpr::Mode::UNARY_OP;
+ expr1 = expr;
+ unaryOp = op;
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initLike(SqliteExpr *expr1, bool notKw, LikeOp likeOp, SqliteExpr *expr2, SqliteExpr *expr3)
+{
+ mode = SqliteExpr::Mode::LIKE;
+ this->expr1 = expr1;
+ this->expr2 = expr2;
+ this->expr3 = expr3;
+ this->notKw = notKw;
+ this->like = likeOp;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+
+ if (expr3)
+ expr3->setParent(this);
+}
+
+void SqliteExpr::initNull(SqliteExpr *expr, const QString& value)
+{
+ mode = SqliteExpr::Mode::NOTNULL;
+ expr1 = expr;
+ notNull = notNullOp(value);
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initIs(SqliteExpr *expr1, bool notKw, SqliteExpr *expr2)
+{
+ mode = SqliteExpr::Mode::IS;
+ this->expr1 = expr1;
+ this->notKw = notKw;
+ this->expr2 = expr2;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+}
+
+void SqliteExpr::initBetween(SqliteExpr *expr1, bool notKw, SqliteExpr *expr2, SqliteExpr *expr3)
+{
+ mode = SqliteExpr::Mode::BETWEEN;
+ this->expr1 = expr1;
+ this->expr2 = expr2;
+ this->expr3 = expr3;
+ this->notKw = notKw;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+
+ if (expr3)
+ expr3->setParent(this);
+}
+
+void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, const QList<SqliteExpr*>& exprList)
+{
+ mode = SqliteExpr::Mode::IN;
+ expr1 = expr;
+ this->notKw = notKw;
+ this->exprList = exprList;
+ foreach (SqliteExpr* expr, exprList)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, SqliteSelect *select)
+{
+ mode = SqliteExpr::Mode::IN;
+ expr1 = expr;
+ this->notKw = notKw;
+ this->select = select;
+ if (expr)
+ expr->setParent(this);
+
+ if (select)
+ select->setParent(this);
+}
+
+void SqliteExpr::initIn(SqliteExpr *expr, bool notKw, const QString& name1, const QString& name2)
+{
+ mode = SqliteExpr::Mode::IN;
+ expr1 = expr;
+ this->notKw = notKw;
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+
+ if (expr)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initExists(SqliteSelect *select)
+{
+ mode = SqliteExpr::Mode::EXISTS;
+ this->select = select;
+ if (select)
+ select->setParent(this);
+}
+
+void SqliteExpr::initSubSelect(SqliteSelect *select)
+{
+ mode = SqliteExpr::Mode::SUB_SELECT;
+ this->select = select;
+ if (select)
+ select->setParent(this);
+}
+
+void SqliteExpr::initCase(SqliteExpr *expr1, const QList<SqliteExpr*>& exprList, SqliteExpr *expr2)
+{
+ mode = SqliteExpr::Mode::CASE;
+ this->expr1 = expr1;
+ this->expr2 = expr2;
+ this->exprList = exprList;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+
+ foreach (SqliteExpr* expr, exprList)
+ expr->setParent(this);
+}
+
+void SqliteExpr::initRaise(const QString& type, const QString& text)
+{
+ mode = SqliteExpr::Mode::RAISE;
+ raiseFunction = new SqliteRaise(type, text);
+}
+
+QStringList SqliteExpr::getColumnsInStatement()
+{
+ return getStrListFromValue(column);
+}
+
+QStringList SqliteExpr::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteExpr::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteExpr::getColumnTokensInStatement()
+{
+ TokenList list;
+ if (!column.isNull())
+ {
+ if (!table.isNull())
+ {
+ if (!database.isNull())
+ list << tokens[4];
+ else
+ list << tokens[2];
+ }
+ else
+ list << tokens[0];
+ }
+ return list;
+}
+
+TokenList SqliteExpr::getTableTokensInStatement()
+{
+ TokenList list;
+ if (!table.isNull())
+ {
+ if (!database.isNull())
+ list << tokens[2];
+ else
+ list << tokens[0];
+ }
+
+ return list;
+}
+
+TokenList SqliteExpr::getDatabaseTokensInStatement()
+{
+ TokenList list;
+ if (!database.isNull())
+ list << tokens[0];
+
+ return list;
+}
+
+QList<SqliteStatement::FullObject> SqliteExpr::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+ if (mode != Mode::ID)
+ return result;
+
+ if (!table.isNull())
+ {
+ if (!database.isNull())
+ {
+ FullObject dbFullObject = getDbFullObject(tokens[0]);
+ result << dbFullObject;
+ dbTokenForFullObjects = dbFullObject.database;
+
+ result << getFullObject(FullObject::TABLE, dbTokenForFullObjects, tokens[2]);
+ }
+ else
+ result << getFullObject(FullObject::TABLE, dbTokenForFullObjects, tokens[0]);
+ }
+
+ return result;
+}
+
+void SqliteExpr::initId(const QString &db, const QString &table, const QString &column)
+{
+ mode = SqliteExpr::Mode::ID;
+ database = db;
+ this->table = table;
+ this->column = column;
+}
+
+void SqliteExpr::initId(const QString& table, const QString& column)
+{
+ mode = SqliteExpr::Mode::ID;
+ this->table = table;
+ this->column = column;
+}
+
+void SqliteExpr::initId(const QString& column)
+{
+ mode = SqliteExpr::Mode::ID;
+ this->column = column;
+}
+
+TokenList SqliteExpr::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ switch (mode)
+ {
+ case SqliteExpr::Mode::null:
+ break;
+ case SqliteExpr::Mode::LITERAL_VALUE:
+ {
+ if (literalNull)
+ builder.withKeyword("NULL");
+ else
+ builder.withLiteralValue(literalValue);
+ break;
+ }
+ case SqliteExpr::Mode::CTIME:
+ builder.withKeyword(ctime.toUpper());
+ break;
+ case SqliteExpr::Mode::BIND_PARAM:
+ builder.withBindParam(bindParam);
+ break;
+ case SqliteExpr::Mode::ID:
+ builder.withTokens(rebuildId());
+ break;
+ case SqliteExpr::Mode::UNARY_OP:
+ builder.withOperator(unaryOp).withSpace().withStatement(expr1);
+ break;
+ case SqliteExpr::Mode::BINARY_OP:
+ builder.withStatement(expr1).withSpace().withOperator(binaryOp).withSpace().withStatement(expr2);
+ break;
+ case SqliteExpr::Mode::FUNCTION:
+ builder.withOther(function).withParLeft().withStatementList(exprList).withParRight();
+ break;
+ case SqliteExpr::Mode::SUB_EXPR:
+ builder.withParLeft().withStatement(expr1).withParRight();
+ break;
+ case SqliteExpr::Mode::CAST:
+ builder.withKeyword("CAST").withSpace().withParLeft().withStatement(expr1).withSpace().withKeyword("AS")
+ .withStatement(columnType).withParRight();
+ break;
+ case SqliteExpr::Mode::COLLATE:
+ builder.withStatement(expr1).withSpace().withKeyword("COLLATE").withSpace().withOther(collation, dialect);
+ break;
+ case SqliteExpr::Mode::LIKE:
+ builder.withTokens(rebuildLike());
+ break;
+ case SqliteExpr::Mode::NULL_:
+ builder.withKeyword("NULL");
+ break;
+ case SqliteExpr::Mode::NOTNULL:
+ builder.withTokens(rebuildNotNull());
+ break;
+ case SqliteExpr::Mode::IS:
+ builder.withTokens(rebuildIs());
+ break;
+ case SqliteExpr::Mode::BETWEEN:
+ builder.withTokens(rebuildBetween());
+ break;
+ case SqliteExpr::Mode::IN:
+ builder.withTokens(rebuildIn());
+ break;
+ case SqliteExpr::Mode::EXISTS:
+ builder.withKeyword("EXISTS").withParLeft().withStatement(select).withParRight();
+ break;
+ case SqliteExpr::Mode::CASE:
+ builder.withTokens(rebuildCase());
+ break;
+ case SqliteExpr::Mode::SUB_SELECT:
+ builder.withParLeft().withStatement(select).withParRight();
+ break;
+ case SqliteExpr::Mode::RAISE:
+ builder.withStatement(raiseFunction);
+ break;
+ }
+
+ return builder.build();
+}
+
+void SqliteExpr::evaluatePostParsing()
+{
+ if (tokens.size() > 0)
+ {
+ QString val = tokens.first()->value;
+ if (val[0] == '"' && val[0] == val[val.length() - 1])
+ possibleDoubleQuotedString = true;
+ }
+}
+
+TokenList SqliteExpr::rebuildId()
+{
+ StatementTokenBuilder builder;
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ if (!table.isNull())
+ builder.withOther(table, dialect).withOperator(".");
+
+ if (possibleDoubleQuotedString)
+ builder.withStringPossiblyOther(column, dialect);
+ else
+ builder.withOther(column, dialect);
+
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildLike()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(expr1).withSpace();
+ if (notKw)
+ builder.withKeyword("NOT").withSpace();
+
+ builder.withKeyword(likeOp(like)).withSpace().withStatement(expr2);
+ if (expr3)
+ builder.withSpace().withKeyword("ESCAPE").withStatement(expr3);
+
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildNotNull()
+{
+ StatementTokenBuilder builder;
+ switch (notNull)
+ {
+ case SqliteExpr::NotNull::ISNULL:
+ builder.withKeyword("ISNULL");
+ break;
+ case SqliteExpr::NotNull::NOT_NULL:
+ builder.withKeyword("NOT").withSpace().withKeyword("NULL");
+ break;
+ case SqliteExpr::NotNull::NOTNULL:
+ builder.withKeyword("NOTNULL");
+ break;
+ case SqliteExpr::NotNull::null:
+ break;
+ }
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildIs()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(expr1).withSpace().withKeyword("IS");
+ if (notKw)
+ builder.withSpace().withKeyword("NOT");
+
+ builder.withStatement(expr2);
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildBetween()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(expr1);
+
+ if (notKw)
+ builder.withSpace().withKeyword("NOT");
+
+ builder.withSpace().withKeyword("BETWEEN").withStatement(expr2).withSpace().withKeyword("AND").withStatement(expr3);
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildIn()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(expr1);
+
+ if (notKw)
+ builder.withSpace().withKeyword("NOT");
+
+ builder.withSpace().withKeyword("IN").withSpace();
+ if (select)
+ {
+ builder.withParLeft().withStatement(select).withParRight();
+ }
+ else if (exprList.size() > 0)
+ {
+ builder.withParLeft().withStatementList(exprList).withParRight();
+ }
+ else
+ {
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect);
+ }
+ return builder.build();
+}
+
+TokenList SqliteExpr::rebuildCase()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("CASE");
+ if (expr1)
+ builder.withStatement(expr1);
+
+ builder.withSpace();
+
+ bool then = false;
+ foreach (SqliteExpr* expr, exprList)
+ {
+ if (then)
+ builder.withKeyword("THEN");
+ else
+ builder.withKeyword("WHEN");
+
+ builder.withStatement(expr).withSpace();
+ then = !then;
+ }
+
+ if (expr2)
+ builder.withKeyword("ELSE").withStatement(expr2).withSpace();
+
+ builder.withKeyword("END");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h
new file mode 100644
index 0000000..f57004f
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteexpr.h
@@ -0,0 +1,144 @@
+#ifndef SQLITEEXPR_H
+#define SQLITEEXPR_H
+
+#include "sqlitestatement.h"
+#include <QString>
+#include <QVariant>
+#include <QList>
+
+class SqliteSelect;
+class SqliteColumnType;
+class SqliteRaise;
+
+class API_EXPORT SqliteExpr : public SqliteStatement
+{
+ public:
+ enum class Mode
+ {
+ null,
+ LITERAL_VALUE,
+ CTIME,
+ BIND_PARAM,
+ ID,
+ UNARY_OP,
+ BINARY_OP,
+ FUNCTION,
+ SUB_EXPR,
+ CAST,
+ COLLATE, // in Sqlite2 exists only in expr of sortlist
+ LIKE,
+ NULL_,
+ NOTNULL,
+ IS,
+ BETWEEN,
+ IN,
+ EXISTS,
+ CASE,
+ SUB_SELECT,
+ RAISE
+ };
+
+ enum class NotNull
+ {
+ ISNULL,
+ NOT_NULL,
+ NOTNULL,
+ null
+ };
+
+ enum class LikeOp
+ {
+ LIKE,
+ GLOB,
+ REGEXP,
+ MATCH,
+ null
+ };
+
+ SqliteExpr();
+ SqliteExpr(const SqliteExpr& other);
+ ~SqliteExpr();
+
+ static LikeOp likeOp(const QString& value);
+ static QString likeOp(LikeOp value);
+ static NotNull notNullOp(const QString& value);
+ static QString notNullOp(NotNull value);
+
+ SqliteStatement* clone();
+ void initLiteral(const QVariant& value);
+ void initNull();
+ void initCTime(const QString& name);
+ void initSubExpr(SqliteExpr* expr);
+ void initId(const QString& db, const QString& table, const QString& column);
+ void initId(const QString& table, const QString& column);
+ void initId(const QString& column);
+ void initBindParam(const QString& value);
+ void initCollate(SqliteExpr* expr, const QString& value);
+ void initCast(SqliteExpr* expr, SqliteColumnType* type);
+ void initFunction(const QString& fnName, int distinct, const QList<SqliteExpr*>& exprList);
+ void initFunction(const QString& fnName, bool star = false);
+ void initBinOp(SqliteExpr* expr1, const QString& op, SqliteExpr* expr2);
+ void initUnaryOp(SqliteExpr* expr, const QString& op);
+ void initLike(SqliteExpr* expr1, bool notKw, SqliteExpr::LikeOp likeOp, SqliteExpr* expr2, SqliteExpr* expr3 = nullptr);
+ void initNull(SqliteExpr* expr, const QString& value);
+ void initIs(SqliteExpr* expr1, bool notKw, SqliteExpr* expr2);
+ void initBetween(SqliteExpr* expr1, bool notKw, SqliteExpr* expr2, SqliteExpr* expr3);
+ void initIn(SqliteExpr* expr, bool notKw, const QList<SqliteExpr*>& exprList);
+ void initIn(SqliteExpr* expr, bool notKw, SqliteSelect* select);
+ void initIn(SqliteExpr* expr, bool notKw, const QString& name1, const QString& name2);
+ void initExists(SqliteSelect* select);
+ void initSubSelect(SqliteSelect* select);
+ void initCase(SqliteExpr* expr1, const QList<SqliteExpr*>& exprList, SqliteExpr* expr2);
+ void initRaise(const QString& type, const QString& text = QString::null);
+
+ Mode mode = Mode::null;
+ QVariant literalValue = QVariant();
+ bool literalNull = false;
+ QString bindParam = QString::null;
+ QString database = QString::null;
+ QString table = QString::null;
+ QString column = QString::null;
+ QString unaryOp = QString::null;
+ QString binaryOp = QString::null;
+ QString function = QString::null;
+ QString collation = QString::null;
+ QString ctime = QString::null;
+ SqliteColumnType* columnType = nullptr;
+ SqliteExpr* expr1 = nullptr;
+ SqliteExpr* expr2 = nullptr;
+ SqliteExpr* expr3 = nullptr;
+ QList<SqliteExpr*> exprList;
+ SqliteSelect* select = nullptr;
+ bool distinctKw = false;
+ bool allKw = false; // alias for DISTINCT as for sqlite3 grammar
+ bool star = false;
+ bool notKw = false;
+ LikeOp like = LikeOp::null;
+ NotNull notNull = NotNull::null;
+ SqliteRaise* raiseFunction = nullptr;
+ bool possibleDoubleQuotedString = false;
+
+ protected:
+ QStringList getColumnsInStatement();
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+ void evaluatePostParsing();
+
+ private:
+ TokenList rebuildId();
+ TokenList rebuildLike();
+ TokenList rebuildNotNull();
+ TokenList rebuildIs();
+ TokenList rebuildBetween();
+ TokenList rebuildIn();
+ TokenList rebuildCase();
+};
+
+typedef QSharedPointer<SqliteExpr> SqliteExprPtr;
+
+#endif // SQLITEEXPR_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.cpp
new file mode 100644
index 0000000..9a29db2
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.cpp
@@ -0,0 +1,187 @@
+#include "sqliteforeignkey.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+#include <QDebug>
+
+SqliteForeignKey::Condition::Condition(SqliteForeignKey::Condition::Action action, SqliteForeignKey::Condition::Reaction reaction)
+{
+ this->action = action;
+ this->reaction = reaction;
+}
+
+SqliteForeignKey::Condition::Condition(const QString &name)
+{
+ this->action = SqliteForeignKey::Condition::MATCH;
+ this->name = name;
+}
+
+SqliteForeignKey::Condition::Condition(const SqliteForeignKey::Condition& other) :
+ SqliteStatement(other), action(other.action), name(other.name), reaction(other.reaction)
+{
+}
+
+QString SqliteForeignKey::Condition::toString(SqliteForeignKey::Condition::Reaction reaction)
+{
+ switch (reaction)
+ {
+ case SqliteForeignKey::Condition::SET_NULL:
+ return "SET NULL";
+ case SqliteForeignKey::Condition::SET_DEFAULT:
+ return "SET DEFAULT";
+ case SqliteForeignKey::Condition::CASCADE:
+ return "CASCADE";
+ case SqliteForeignKey::Condition::RESTRICT:
+ return "RESTRICT";
+ case SqliteForeignKey::Condition::NO_ACTION:
+ return "NO ACTION";
+ }
+ return QString::null;
+}
+
+SqliteForeignKey::Condition::Reaction SqliteForeignKey::Condition::toEnum(const QString& reaction)
+{
+ QString upper = reaction.toUpper();
+ if (upper == "SET NULL")
+ return SET_NULL;
+
+ if (upper == "SET DEFAULT")
+ return SET_DEFAULT;
+
+ if (upper == "CASCADE")
+ return CASCADE;
+
+ if (upper == "RESTRICT")
+ return RESTRICT;
+
+ if (upper == "NO ACTION")
+ return NO_ACTION;
+
+ qCritical() << "Unknown Reaction value. Cannot convert to Condition::Reaction. Returning default, the SET_NULL.";
+ return SET_NULL;
+}
+
+SqliteStatement*SqliteForeignKey::Condition::clone()
+{
+ return new SqliteForeignKey::Condition(*this);
+}
+
+SqliteForeignKey::SqliteForeignKey()
+{
+}
+
+SqliteForeignKey::SqliteForeignKey(const SqliteForeignKey& other) :
+ SqliteStatement(other), foreignTable(other.foreignTable), deferrable(other.deferrable), initially(other.initially)
+{
+ DEEP_COPY_COLLECTION(SqliteIndexedColumn, indexedColumns);
+ DEEP_COPY_COLLECTION(Condition, conditions);
+}
+
+SqliteForeignKey::~SqliteForeignKey()
+{
+}
+
+SqliteStatement*SqliteForeignKey::clone()
+{
+ return new SqliteForeignKey(*this);
+}
+
+QStringList SqliteForeignKey::getTablesInStatement()
+{
+ return getStrListFromValue(foreignTable);
+}
+
+TokenList SqliteForeignKey::getTableTokensInStatement()
+{
+ return parentStatement()->getContextTableTokens(false, false);
+}
+
+QList<SqliteStatement::FullObject> SqliteForeignKey::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj;
+ TokenList tokens = getTableTokensInStatement();
+ if (tokens.size() > 0)
+ fullObj = getFullObject(FullObject::TABLE, dbTokenForFullObjects, tokens[0]);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+TokenList SqliteForeignKey::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("REFERENCES").withSpace().withOther(foreignTable, dialect);
+
+ if (indexedColumns.size() > 0)
+ builder.withSpace().withParLeft().withStatementList(indexedColumns).withParRight();
+
+ if (conditions.size() > 0)
+ builder.withSpace().withStatementList(conditions, "");
+
+ if (deferrable != SqliteDeferrable::null)
+ {
+ if (deferrable == SqliteDeferrable::NOT_DEFERRABLE)
+ builder.withSpace().withKeyword("NOT").withSpace().withKeyword("DEFERRABLE");
+ else if (deferrable == SqliteDeferrable::DEFERRABLE)
+ builder.withSpace().withKeyword("DEFERRABLE");
+
+ if (initially != SqliteInitially::null)
+ builder.withSpace().withKeyword("INITIALLY").withSpace().withKeyword(sqliteInitially(initially));
+ }
+
+ return builder.build();
+}
+
+
+TokenList SqliteForeignKey::Condition::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ switch (action)
+ {
+ case SqliteForeignKey::Condition::UPDATE:
+ builder.withKeyword("ON").withSpace().withKeyword("UPDATE").withSpace();
+ applyReactionToBuilder(builder);
+ break;
+ case SqliteForeignKey::Condition::INSERT:
+ builder.withKeyword("ON").withSpace().withKeyword("INSERT").withSpace();
+ applyReactionToBuilder(builder);
+ break;
+ case SqliteForeignKey::Condition::DELETE:
+ builder.withKeyword("ON").withSpace().withKeyword("DELETE").withSpace();
+ applyReactionToBuilder(builder);
+ break;
+ case SqliteForeignKey::Condition::MATCH:
+ builder.withKeyword("MATCH").withSpace().withOther(name);
+ break;
+ }
+
+ return builder.build();
+}
+
+void SqliteForeignKey::Condition::applyReactionToBuilder(StatementTokenBuilder& builder)
+{
+ switch (reaction)
+ {
+ case SqliteForeignKey::Condition::SET_NULL:
+ builder.withKeyword("SET").withSpace().withKeyword("NULL");
+ break;
+ case SqliteForeignKey::Condition::SET_DEFAULT:
+ builder.withKeyword("SET").withSpace().withKeyword("DEFAULT");
+ break;
+ case SqliteForeignKey::Condition::CASCADE:
+ builder.withKeyword("CASCADE");
+ break;
+ case SqliteForeignKey::Condition::RESTRICT:
+ builder.withKeyword("RESTRICT");
+ break;
+ case SqliteForeignKey::Condition::NO_ACTION:
+ builder.withKeyword("NO").withSpace().withKeyword("ACTION");
+ break;
+ }
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.h
new file mode 100644
index 0000000..18e0bcb
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteforeignkey.h
@@ -0,0 +1,75 @@
+#ifndef SQLITEFOREIGNKEY_H
+#define SQLITEFOREIGNKEY_H
+
+#include "sqlitestatement.h"
+#include "sqliteindexedcolumn.h"
+#include "sqlitedeferrable.h"
+#include "parser/statementtokenbuilder.h"
+#include <QList>
+#include <QString>
+
+class API_EXPORT SqliteForeignKey : public SqliteStatement
+{
+ public:
+ class API_EXPORT Condition : public SqliteStatement
+ {
+ public:
+ enum Action
+ {
+ UPDATE,
+ INSERT,
+ DELETE,
+ MATCH
+ };
+
+ enum Reaction
+ {
+ SET_NULL,
+ SET_DEFAULT,
+ CASCADE,
+ RESTRICT,
+ NO_ACTION
+ };
+
+ Condition(Action action, Reaction reaction);
+ explicit Condition(const QString& name);
+ Condition(const Condition& other);
+
+ static QString toString(Reaction reaction);
+ static Reaction toEnum(const QString& reaction);
+
+ SqliteStatement* clone();
+
+ Action action;
+ QString name = QString::null;
+ Reaction reaction = NO_ACTION;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void applyReactionToBuilder(StatementTokenBuilder& builder);
+ };
+
+ SqliteForeignKey();
+ SqliteForeignKey(const SqliteForeignKey& other);
+ ~SqliteForeignKey();
+
+ SqliteStatement* clone();
+
+ QString foreignTable = QString::null;
+ QList<SqliteIndexedColumn*> indexedColumns;
+ QList<Condition*> conditions;
+ SqliteDeferrable deferrable = SqliteDeferrable::null; // Those two are for table constraint only,
+ SqliteInitially initially = SqliteInitially::null; // because column has its own fields for that.
+
+ protected:
+ QStringList getTablesInStatement();
+ TokenList getTableTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteForeignKey> SqliteForeignKeyPtr;
+
+#endif // SQLITEFOREIGNKEY_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.cpp
new file mode 100644
index 0000000..5e65eab
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.cpp
@@ -0,0 +1,52 @@
+#include "sqliteindexedcolumn.h"
+#include "parser/statementtokenbuilder.h"
+
+SqliteIndexedColumn::SqliteIndexedColumn()
+{
+}
+
+SqliteIndexedColumn::SqliteIndexedColumn(const SqliteIndexedColumn& other) :
+ SqliteStatement(other), name(other.name), sortOrder(other.sortOrder), collate(other.collate)
+{
+}
+
+SqliteIndexedColumn::SqliteIndexedColumn(const QString &name, const QString &collate, SqliteSortOrder sortOrder)
+ : SqliteIndexedColumn()
+{
+ this->name = name;
+ this->sortOrder = sortOrder;
+ this->collate = collate;
+}
+
+SqliteIndexedColumn::SqliteIndexedColumn(const QString& name)
+ : SqliteIndexedColumn()
+{
+ this->name = name;
+}
+
+SqliteStatement*SqliteIndexedColumn::clone()
+{
+ return new SqliteIndexedColumn(*this);
+}
+
+QStringList SqliteIndexedColumn::getColumnsInStatement()
+{
+ return getStrListFromValue(name);
+}
+
+TokenList SqliteIndexedColumn::getColumnTokensInStatement()
+{
+ return getTokenListFromNamedKey("nm");
+}
+
+
+TokenList SqliteIndexedColumn::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withOther(name, dialect);
+ if (!collate.isNull())
+ builder.withSpace().withKeyword("COLLATE").withSpace().withOther(collate, dialect);
+
+ builder.withSortOrder(sortOrder);
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.h
new file mode 100644
index 0000000..c013d17
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteindexedcolumn.h
@@ -0,0 +1,30 @@
+#ifndef SQLITEINDEXEDCOLUMN_H
+#define SQLITEINDEXEDCOLUMN_H
+
+#include "sqlitestatement.h"
+#include "sqlitesortorder.h"
+#include <QString>
+
+class API_EXPORT SqliteIndexedColumn : public SqliteStatement
+{
+ public:
+ SqliteIndexedColumn();
+ SqliteIndexedColumn(const SqliteIndexedColumn& other);
+ SqliteIndexedColumn(const QString& name, const QString& collate, SqliteSortOrder sortOrder);
+ explicit SqliteIndexedColumn(const QString& name);
+
+ SqliteStatement* clone();
+
+ QString name = QString::null;
+ SqliteSortOrder sortOrder = SqliteSortOrder::null;
+ QString collate = QString::null;
+
+ protected:
+ QStringList getColumnsInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteIndexedColumn> SqliteIndexedColumnPtr;
+
+#endif // SQLITEINDEXEDCOLUMN_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp
new file mode 100644
index 0000000..6c26e8d
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.cpp
@@ -0,0 +1,214 @@
+#include "sqliteinsert.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "sqliteselect.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+#include "sqlitewith.h"
+
+SqliteInsert::SqliteInsert()
+{
+ queryType = SqliteQueryType::Insert;
+}
+
+SqliteInsert::SqliteInsert(const SqliteInsert& other) :
+ SqliteQuery(other), replaceKw(other.replaceKw), defaultValuesKw(other.defaultValuesKw), onConflict(other.onConflict), database(other.database),
+ table(other.table), columnNames(other.columnNames)
+{
+ DEEP_COPY_COLLECTION(SqliteExpr, values);
+ DEEP_COPY_FIELD(SqliteSelect, select);
+ DEEP_COPY_FIELD(SqliteWith, with);
+}
+
+SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns,
+ const QList<SqliteExpr *> &row, SqliteWith* with) :
+ SqliteInsert()
+{
+ initName(name1, name2);
+ initMode(replace, onConflict);
+ columnNames = columns;
+ values = row;
+
+ this->with = with;
+ if (with)
+ with->setParent(this);
+
+ foreach (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) :
+ SqliteInsert()
+{
+ initName(name1, name2);
+ initMode(replace, onConflict);
+
+ this->with = with;
+ if (with)
+ with->setParent(this);
+
+ columnNames = columns;
+ this->select = select;
+ if (select)
+ select->setParent(this);
+}
+
+SqliteInsert::SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString &name1, const QString &name2, const QList<QString> &columns,
+ SqliteWith* with) :
+ SqliteInsert()
+{
+ initName(name1, name2);
+ initMode(replace, onConflict);
+
+ this->with = with;
+ if (with)
+ with->setParent(this);
+
+ columnNames = columns;
+ defaultValuesKw = true;
+}
+
+SqliteInsert::~SqliteInsert()
+{
+}
+
+SqliteStatement*SqliteInsert::clone()
+{
+ return new SqliteInsert(*this);
+}
+
+QStringList SqliteInsert::getColumnsInStatement()
+{
+ QStringList columns;
+ columns += columnNames;
+ return columns;
+}
+
+QStringList SqliteInsert::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteInsert::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteInsert::getColumnTokensInStatement()
+{
+ TokenList list;
+ foreach (TokenPtr token, getTokenListFromNamedKey("inscollist_opt", -1))
+ {
+ if (token->type != Token::OTHER && token->type != Token::KEYWORD)
+ continue;
+
+ list << token;
+ }
+ return list;
+}
+
+TokenList SqliteInsert::getTableTokensInStatement()
+{
+ return getObjectTokenListFromFullname();
+}
+
+TokenList SqliteInsert::getDatabaseTokensInStatement()
+{
+ if (tokensMap.contains("fullname"))
+ return getDbTokenListFromFullname();
+
+ if (tokensMap.contains("nm"))
+ return extractPrintableTokens(tokensMap["nm"]);
+
+ return TokenList();
+}
+
+QList<SqliteStatement::FullObject> SqliteInsert::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+ if (!tokensMap.contains("fullname"))
+ return result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+void SqliteInsert::initName(const QString& name1, const QString& name2)
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+void SqliteInsert::initMode(bool replace, SqliteConflictAlgo onConflict)
+{
+ replaceKw = replace;
+ this->onConflict = onConflict;
+}
+
+TokenList SqliteInsert::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (with)
+ builder.withStatement(with);
+
+ if (replaceKw)
+ {
+ builder.withKeyword("REPLACE").withSpace();
+ }
+ else
+ {
+ builder.withKeyword("INSERT").withSpace();
+ if (onConflict != SqliteConflictAlgo::null)
+ builder.withKeyword("OR").withSpace().withKeyword(sqliteConflictAlgo(onConflict)).withSpace();
+ }
+
+ builder.withKeyword("INTO").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect).withSpace();
+
+ if (defaultValuesKw)
+ {
+ builder.withKeyword("DEFAULT").withSpace().withKeyword("VALUES");
+ }
+ else
+ {
+ if (columnNames.size() > 0)
+ builder.withParLeft().withOtherList(columnNames, dialect).withParRight().withSpace();
+
+ if (select)
+ {
+ builder.withStatement(select);
+ }
+ else if (dialect == Dialect::Sqlite2) // Sqlite2 uses classic single row values
+ {
+ builder.withKeyword("VALUES").withSpace().withParLeft().withStatementList(values).withParRight();
+ }
+ }
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h
new file mode 100644
index 0000000..4287680
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteinsert.h
@@ -0,0 +1,57 @@
+#ifndef SQLITEINSERT_H
+#define SQLITEINSERT_H
+
+#include "sqlitequery.h"
+#include "sqliteconflictalgo.h"
+#include <QString>
+#include <QList>
+
+class SqliteSelect;
+class SqliteExpr;
+class SqliteWith;
+
+class API_EXPORT SqliteInsert : public SqliteQuery
+{
+ public:
+ SqliteInsert();
+ SqliteInsert(const SqliteInsert& other);
+ SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1,
+ 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);
+ SqliteInsert(bool replace, SqliteConflictAlgo onConflict, const QString& name1,
+ const QString& name2, const QList<QString>& columns, SqliteWith* with);
+ ~SqliteInsert();
+
+ SqliteStatement* clone();
+
+ protected:
+ QStringList getColumnsInStatement();
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void initName(const QString& name1, const QString& name2);
+ void initMode(bool replace, SqliteConflictAlgo onConflict);
+
+ public:
+ bool replaceKw = false;
+ bool defaultValuesKw = false;
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ QString database = QString::null;
+ QString table = QString::null;
+ QStringList columnNames;
+ QList<SqliteExpr*> values;
+ SqliteSelect* select = nullptr;
+ SqliteWith* with = nullptr;
+};
+
+typedef QSharedPointer<SqliteInsert> SqliteInsertPtr;
+
+#endif // SQLITEINSERT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.cpp
new file mode 100644
index 0000000..c44228a
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.cpp
@@ -0,0 +1,79 @@
+#include "sqlitelimit.h"
+#include "sqliteexpr.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+
+SqliteLimit::SqliteLimit()
+{
+}
+
+SqliteLimit::SqliteLimit(const SqliteLimit& other) :
+ SqliteStatement(other)
+{
+ DEEP_COPY_FIELD(SqliteExpr, limit);
+ DEEP_COPY_FIELD(SqliteExpr, offset);
+}
+
+SqliteLimit::SqliteLimit(SqliteExpr *expr)
+{
+ limit = expr;
+ if (expr)
+ expr->setParent(this);
+}
+
+SqliteLimit::SqliteLimit(SqliteExpr *expr1, SqliteExpr *expr2, bool offsetKeyword)
+{
+ limit = expr1;
+ offset = expr2;
+ offsetKw = offsetKeyword;
+ if (expr1)
+ expr1->setParent(this);
+
+ if (expr2)
+ expr2->setParent(this);
+}
+
+SqliteLimit::SqliteLimit(const QVariant &positiveInt)
+{
+ limit = new SqliteExpr();
+ limit->initLiteral(positiveInt);
+ limit->setParent(this);
+}
+
+SqliteLimit::SqliteLimit(const QVariant &positiveInt1, const QVariant &positiveInt2)
+{
+ limit = new SqliteExpr();
+ limit->initLiteral(positiveInt1);
+ limit->setParent(this);
+
+ offset = new SqliteExpr();
+ offset->initLiteral(positiveInt2);
+ offset->setParent(this);
+}
+
+SqliteLimit::~SqliteLimit()
+{
+}
+
+SqliteStatement*SqliteLimit::clone()
+{
+ return new SqliteLimit(*this);
+}
+
+
+TokenList SqliteLimit::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("LIMIT").withStatement(limit);
+ if (offset)
+ {
+ if (offsetKw)
+ builder.withSpace().withKeyword("OFFSET");
+ else
+ builder.withOperator(",");
+
+ builder.withStatement(offset);
+ }
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.h
new file mode 100644
index 0000000..284cf49
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitelimit.h
@@ -0,0 +1,31 @@
+#ifndef SQLITELIMIT_H
+#define SQLITELIMIT_H
+
+#include "sqlitestatement.h"
+
+class SqliteExpr;
+
+class API_EXPORT SqliteLimit : public SqliteStatement
+{
+ public:
+ SqliteLimit();
+ SqliteLimit(const SqliteLimit& other);
+ explicit SqliteLimit(SqliteExpr* expr);
+ SqliteLimit(SqliteExpr* expr1, SqliteExpr* expr2, bool offsetKeyword);
+ explicit SqliteLimit(const QVariant& positiveInt);
+ SqliteLimit(const QVariant& positiveInt1, const QVariant& positiveInt2);
+ ~SqliteLimit();
+
+ SqliteStatement* clone();
+
+ SqliteExpr* limit = nullptr;
+ SqliteExpr* offset = nullptr;
+ bool offsetKw = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteLimit> SqliteLimitPtr;
+
+#endif // SQLITELIMIT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.cpp
new file mode 100644
index 0000000..3bb1b44
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.cpp
@@ -0,0 +1,41 @@
+#include "sqliteorderby.h"
+#include "sqliteexpr.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+
+SqliteOrderBy::SqliteOrderBy()
+{
+}
+
+SqliteOrderBy::SqliteOrderBy(const SqliteOrderBy& other) :
+ SqliteStatement(other), order(other.order)
+{
+ DEEP_COPY_FIELD(SqliteExpr, expr);
+}
+
+SqliteOrderBy::SqliteOrderBy(SqliteExpr *expr, SqliteSortOrder order)
+{
+ this->expr = expr;
+ this->order = order;
+ if (expr)
+ expr->setParent(this);
+}
+
+SqliteOrderBy::~SqliteOrderBy()
+{
+}
+
+SqliteStatement*SqliteOrderBy::clone()
+{
+ return new SqliteOrderBy(*this);
+}
+
+TokenList SqliteOrderBy::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(expr);
+ if (order != SqliteSortOrder::null)
+ builder.withSpace().withKeyword(sqliteSortOrder(order));
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.h
new file mode 100644
index 0000000..598423d
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteorderby.h
@@ -0,0 +1,28 @@
+#ifndef SQLITEORDERBY_H
+#define SQLITEORDERBY_H
+
+#include "sqlitestatement.h"
+#include "sqlitesortorder.h"
+
+class SqliteExpr;
+
+class API_EXPORT SqliteOrderBy : public SqliteStatement
+{
+ public:
+ SqliteOrderBy();
+ SqliteOrderBy(const SqliteOrderBy& other);
+ SqliteOrderBy(SqliteExpr* expr, SqliteSortOrder order);
+ ~SqliteOrderBy();
+
+ SqliteStatement* clone();
+
+ SqliteExpr* expr = nullptr;
+ SqliteSortOrder order;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteOrderBy> SqliteOrderByPtr;
+
+#endif // SQLITEORDERBY_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.cpp
new file mode 100644
index 0000000..0e4f056
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.cpp
@@ -0,0 +1,109 @@
+#include "sqlitepragma.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqlitePragma::SqlitePragma()
+{
+ queryType = SqliteQueryType::Pragma;
+}
+
+SqlitePragma::SqlitePragma(const SqlitePragma& other) :
+ SqliteQuery(other), database(other.database), pragmaName(other.pragmaName), value(other.value), equalsOp(other.equalsOp), parenthesis(other.parenthesis)
+{
+}
+
+SqlitePragma::SqlitePragma(const QString &name1, const QString &name2)
+ : SqlitePragma()
+{
+ initName(name1, name2);
+}
+
+SqlitePragma::SqlitePragma(const QString &name1, const QString &name2, const QVariant& value, bool equals)
+ : SqlitePragma()
+{
+ initName(name1, name2);
+ this->value = value;
+ if (equals)
+ equalsOp = true;
+ else
+ parenthesis = true;
+}
+
+SqlitePragma::SqlitePragma(const QString &name1, const QString &name2, const QString &value, bool equals)
+ : SqlitePragma()
+{
+ initName(name1, name2);
+ this->value = value;
+ if (equals)
+ equalsOp = true;
+ else
+ parenthesis = true;
+}
+
+SqliteStatement*SqlitePragma::clone()
+{
+ return new SqlitePragma(*this);
+}
+
+QStringList SqlitePragma::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqlitePragma::getDatabaseTokensInStatement()
+{
+ if (dialect == Dialect::Sqlite2 || database.isNull())
+ return TokenList();
+
+ return getTokenListFromNamedKey("nm");
+}
+
+QList<SqliteStatement::FullObject> SqlitePragma::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+ if (dialect == Dialect::Sqlite2 || database.isNull())
+ return result;
+
+ // Db object
+ FullObject fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+void SqlitePragma::initName(const QString &name1, const QString &name2)
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ pragmaName = name2;
+ }
+ else
+ pragmaName = name1;
+}
+
+TokenList SqlitePragma::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("PRAGMA").withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(pragmaName, dialect);
+
+ if (equalsOp)
+ builder.withSpace().withOperator("=").withSpace().withLiteralValue(value);
+ else if (parenthesis)
+ builder.withParLeft().withLiteralValue(value).withParRight();
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.h
new file mode 100644
index 0000000..364a16f
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitepragma.h
@@ -0,0 +1,41 @@
+#ifndef SQLITEPRAGMA_H
+#define SQLITEPRAGMA_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+#include <QVariant>
+
+class API_EXPORT SqlitePragma : public SqliteQuery
+{
+ public:
+ SqlitePragma();
+ SqlitePragma(const SqlitePragma& other);
+ SqlitePragma(const QString& name1, const QString& name2);
+ SqlitePragma(const QString& name1, const QString& name2, const QVariant& value,
+ bool equals);
+ SqlitePragma(const QString& name1, const QString& name2, const QString& value,
+ bool equals);
+
+ SqliteStatement* clone();
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+
+ private:
+ void initName(const QString& name1, const QString& name2);
+
+ public:
+ QString database = QString::null;
+ QString pragmaName = QString::null;
+ QVariant value = QVariant();
+ bool equalsOp = false;
+ bool parenthesis = false;
+};
+
+typedef QSharedPointer<SqlitePragma> SqlitePragmaPtr;
+
+#endif // SQLITEPRAGMA_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.cpp
new file mode 100644
index 0000000..19c3c40
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.cpp
@@ -0,0 +1,51 @@
+#include "sqlitequery.h"
+
+SqliteQuery::SqliteQuery()
+{
+}
+
+SqliteQuery::SqliteQuery(const SqliteQuery& other) :
+ SqliteStatement(other), queryType(other.queryType), explain(other.explain), queryPlan(other.queryPlan)
+{
+}
+
+bool SqliteQuery::isReadOnly()
+{
+ bool readOnly = true;
+ switch (queryType)
+ {
+ case SqliteQueryType::EMPTY:
+ case SqliteQueryType::Analyze:
+ case SqliteQueryType::Pragma:
+ case SqliteQueryType::Select:
+ readOnly = true;
+ break;
+ case SqliteQueryType::UNDEFINED:
+ case SqliteQueryType::AlterTable:
+ case SqliteQueryType::Attach:
+ case SqliteQueryType::BeginTrans:
+ case SqliteQueryType::CommitTrans:
+ case SqliteQueryType::Copy:
+ case SqliteQueryType::CreateIndex:
+ case SqliteQueryType::CreateTable:
+ case SqliteQueryType::CreateTrigger:
+ case SqliteQueryType::CreateView:
+ case SqliteQueryType::CreateVirtualTable:
+ case SqliteQueryType::Delete:
+ case SqliteQueryType::Detach:
+ case SqliteQueryType::DropIndex:
+ case SqliteQueryType::DropTable:
+ case SqliteQueryType::DropTrigger:
+ case SqliteQueryType::DropView:
+ case SqliteQueryType::Insert:
+ case SqliteQueryType::Reindex:
+ case SqliteQueryType::Release:
+ case SqliteQueryType::Rollback:
+ case SqliteQueryType::Savepoint:
+ case SqliteQueryType::Update:
+ case SqliteQueryType::Vacuum:
+ readOnly = false;
+ break;
+ }
+ return readOnly;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.h
new file mode 100644
index 0000000..1667dc9
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequery.h
@@ -0,0 +1,30 @@
+#ifndef SQLITEQUERY_H
+#define SQLITEQUERY_H
+
+#include "sqlitestatement.h"
+#include "sqlitequerytype.h"
+
+/**
+ * @addtogroup sqlite_statement
+ * @brief The SqliteQuery class
+ */
+class API_EXPORT SqliteQuery : public SqliteStatement
+{
+ public:
+ SqliteQuery();
+ SqliteQuery(const SqliteQuery& other);
+
+ bool isReadOnly();
+
+ SqliteQueryType queryType = SqliteQueryType::UNDEFINED;
+
+ bool explain = false;
+ bool queryPlan = false;
+};
+
+/**
+ * Shared pointer to SqliteQuery.
+ */
+typedef QSharedPointer<SqliteQuery> SqliteQueryPtr;
+
+#endif // SQLITEQUERY_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.cpp
new file mode 100644
index 0000000..c369e0e
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.cpp
@@ -0,0 +1,66 @@
+#include "sqlitequerytype.h"
+
+QString sqliteQueryTypeToString(const SqliteQueryType& type)
+{
+ switch (type)
+ {
+ case SqliteQueryType::UNDEFINED:
+ return "UNDEFINED";
+ case SqliteQueryType::EMPTY:
+ return "EMPTY";
+ case SqliteQueryType::AlterTable:
+ return "AlterTable";
+ case SqliteQueryType::Analyze:
+ return "Analyze";
+ case SqliteQueryType::Attach:
+ return "Attach";
+ case SqliteQueryType::BeginTrans:
+ return "BeginTrans";
+ case SqliteQueryType::CommitTrans:
+ return "CommitTrans";
+ case SqliteQueryType::Copy:
+ return "Copy";
+ case SqliteQueryType::CreateIndex:
+ return "CreateIndex";
+ case SqliteQueryType::CreateTable:
+ return "CreateTable";
+ case SqliteQueryType::CreateTrigger:
+ return "CreateTrigger";
+ case SqliteQueryType::CreateView:
+ return "CreateView";
+ case SqliteQueryType::CreateVirtualTable:
+ return "CreateVirtualTable";
+ case SqliteQueryType::Delete:
+ return "Delete";
+ case SqliteQueryType::Detach:
+ return "Detach";
+ case SqliteQueryType::DropIndex:
+ return "DropIndex";
+ case SqliteQueryType::DropTable:
+ return "DropTable";
+ case SqliteQueryType::DropTrigger:
+ return "DropTrigger";
+ case SqliteQueryType::DropView:
+ return "DropView";
+ case SqliteQueryType::Insert:
+ return "Insert";
+ case SqliteQueryType::Pragma:
+ return "Pragma";
+ case SqliteQueryType::Reindex:
+ return "Reindex";
+ case SqliteQueryType::Release:
+ return "Release";
+ case SqliteQueryType::Rollback:
+ return "Rollback";
+ case SqliteQueryType::Savepoint:
+ return "Savepoint";
+ case SqliteQueryType::Select:
+ return "Select";
+ case SqliteQueryType::Update:
+ return "Update";
+ case SqliteQueryType::Vacuum:
+ return "Vacuum";
+ default:
+ return QString::null;
+ }
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.h
new file mode 100644
index 0000000..763fcfa
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitequerytype.h
@@ -0,0 +1,41 @@
+#ifndef SQLITEQUERYTYPE_H
+#define SQLITEQUERYTYPE_H
+
+#include "coreSQLiteStudio_global.h"
+#include <QString>
+
+enum class SqliteQueryType
+{
+ UNDEFINED,
+ EMPTY, // still can hold comments
+ AlterTable,
+ Analyze,
+ Attach,
+ BeginTrans,
+ CommitTrans,
+ Copy,
+ CreateIndex,
+ CreateTable,
+ CreateTrigger,
+ CreateView,
+ CreateVirtualTable,
+ Delete,
+ Detach,
+ DropIndex,
+ DropTable,
+ DropTrigger,
+ DropView,
+ Insert,
+ Pragma,
+ Reindex,
+ Release,
+ Rollback,
+ Savepoint,
+ Select,
+ Update,
+ Vacuum
+};
+
+QString API_EXPORT sqliteQueryTypeToString(const SqliteQueryType& type);
+
+#endif // SQLITEQUERYTYPE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.cpp
new file mode 100644
index 0000000..b606baa
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.cpp
@@ -0,0 +1,70 @@
+#include "sqliteraise.h"
+#include "parser/statementtokenbuilder.h"
+
+SqliteRaise::SqliteRaise()
+{
+}
+
+SqliteRaise::SqliteRaise(const SqliteRaise& other) :
+ SqliteStatement(other), type(other.type), message(other.message)
+{
+}
+
+SqliteRaise::SqliteRaise(const QString &type)
+{
+ this->type = raiseType(type);
+}
+
+SqliteRaise::SqliteRaise(const QString &type, const QString &text)
+{
+ this->type = raiseType(type);
+ message = text;
+}
+
+SqliteStatement*SqliteRaise::clone()
+{
+ return new SqliteRaise(*this);
+}
+
+SqliteRaise::Type SqliteRaise::raiseType(const QString &value)
+{
+ QString upper = value.toUpper();
+ if (upper == "IGNORE")
+ return SqliteRaise::Type::IGNORE;
+ else if (upper == "ROLLBACK")
+ return SqliteRaise::Type::ROLLBACK;
+ else if (upper == "ABORT")
+ return SqliteRaise::Type::ABORT;
+ else if (upper == "FAIL")
+ return SqliteRaise::Type::FAIL;
+ else
+ return SqliteRaise::Type::null;
+}
+
+QString SqliteRaise::raiseType(SqliteRaise::Type value)
+{
+ switch (value)
+ {
+ case SqliteRaise::Type::IGNORE:
+ return "IGNORE";
+ case SqliteRaise::Type::ROLLBACK:
+ return "ROLLBACK";
+ case SqliteRaise::Type::ABORT:
+ return "ABORT";
+ case SqliteRaise::Type::FAIL:
+ return "FAIL";
+ default:
+ return QString::null;
+ }
+}
+
+TokenList SqliteRaise::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("RAISE").withSpace().withParLeft().withKeyword(raiseType(type));
+ if (type != Type::IGNORE)
+ builder.withOperator(",").withSpace().withString(message);
+
+ builder.withParRight();
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.h
new file mode 100644
index 0000000..1b844f8
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteraise.h
@@ -0,0 +1,38 @@
+#ifndef SQLITERAISE_H
+#define SQLITERAISE_H
+
+#include "sqlitestatement.h"
+#include <QString>
+
+class API_EXPORT SqliteRaise : public SqliteStatement
+{
+ public:
+ enum class Type
+ {
+ IGNORE,
+ ROLLBACK,
+ ABORT,
+ FAIL,
+ null
+ };
+
+ SqliteRaise();
+ SqliteRaise(const SqliteRaise& other);
+ explicit SqliteRaise(const QString& type);
+ SqliteRaise(const QString& type, const QString& text);
+
+ SqliteStatement* clone();
+
+ static Type raiseType(const QString& value);
+ static QString raiseType(Type value);
+
+ Type type = Type::null;
+ QString message = QString::null;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteRaise> SqliteRaisePtr;
+
+#endif // SQLITERAISE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.cpp
new file mode 100644
index 0000000..7584a37
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.cpp
@@ -0,0 +1,82 @@
+#include "sqlitereindex.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteReindex::SqliteReindex()
+{
+ queryType = SqliteQueryType::Reindex;
+}
+
+SqliteReindex::SqliteReindex(const SqliteReindex& other) :
+ SqliteQuery(other), database(other.database), table(other.table)
+{
+}
+
+SqliteReindex::SqliteReindex(const QString& name1, const QString& name2)
+ : SqliteReindex()
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+}
+
+SqliteStatement*SqliteReindex::clone()
+{
+ return new SqliteReindex(*this);
+}
+
+QStringList SqliteReindex::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteReindex::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteReindex::getTableTokensInStatement()
+{
+ return getObjectTokenListFromNmDbnm();
+}
+
+TokenList SqliteReindex::getDatabaseTokensInStatement()
+{
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteReindex::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromNmDbnm(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+TokenList SqliteReindex::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("REINDEX");
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.h
new file mode 100644
index 0000000..642b5bf
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitereindex.h
@@ -0,0 +1,31 @@
+#ifndef SQLITEREINDEX_H
+#define SQLITEREINDEX_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+
+class API_EXPORT SqliteReindex : public SqliteQuery
+{
+ public:
+ SqliteReindex();
+ SqliteReindex(const SqliteReindex& other);
+ SqliteReindex(const QString& name1, const QString& name2);
+
+ SqliteStatement* clone();
+
+ QString database = QString::null;
+ QString table = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<SqliteStatement::FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteReindex> SqliteReindexPtr;
+
+#endif // SQLITEREINDEX_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.cpp
new file mode 100644
index 0000000..8510524
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.cpp
@@ -0,0 +1,39 @@
+#include "sqliterelease.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteRelease::SqliteRelease()
+{
+ queryType = SqliteQueryType::Release;
+}
+
+SqliteRelease::SqliteRelease(const SqliteRelease& other) :
+ SqliteQuery(other), name(other.name), savepointKw(other.savepointKw)
+{
+}
+
+SqliteRelease::SqliteRelease(bool savepointKw, const QString& name)
+ : SqliteRelease()
+{
+ this->name = name;
+ this->savepointKw = savepointKw;
+}
+
+SqliteStatement*SqliteRelease::clone()
+{
+ return new SqliteRelease(*this);
+}
+
+TokenList SqliteRelease::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("RELEASE").withSpace();
+ if (savepointKw)
+ builder.withKeyword("SAVEPOINT").withSpace();
+
+ builder.withOther(name, dialect).withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.h
new file mode 100644
index 0000000..d115669
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterelease.h
@@ -0,0 +1,26 @@
+#ifndef SQLITERELEASE_H
+#define SQLITERELEASE_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+
+class API_EXPORT SqliteRelease : public SqliteQuery
+{
+ public:
+ SqliteRelease();
+ SqliteRelease(const SqliteRelease& other);
+ SqliteRelease(bool savepointKw, const QString &name);
+
+ SqliteStatement* clone();
+
+ QString name = QString::null;
+ bool savepointKw = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteRelease> SqliteReleasePtr;
+
+#endif // SQLITERELEASE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.cpp
new file mode 100644
index 0000000..a13fd4c
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.cpp
@@ -0,0 +1,57 @@
+#include "sqliterollback.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteRollback::SqliteRollback()
+{
+ queryType = SqliteQueryType::Rollback;
+}
+
+SqliteRollback::SqliteRollback(const SqliteRollback& other) :
+ SqliteQuery(other), transactionKw(other.transactionKw), toKw(other.toKw), savepointKw(other.savepointKw), name(other.name)
+{
+}
+
+SqliteRollback::SqliteRollback(bool transactionKw, const QString& name)
+ : SqliteRollback()
+{
+ this->name = name;
+ this->transactionKw = transactionKw;
+}
+
+SqliteRollback::SqliteRollback(bool transactionKw, bool savePoint, const QString& name)
+{
+ // we ignore name from trans_opt,
+ // it's not officialy supported in sqlite3
+ this->name = name;
+ this->transactionKw = transactionKw;
+ toKw = true;
+ savepointKw = savePoint;
+}
+
+SqliteStatement*SqliteRollback::clone()
+{
+ return new SqliteRollback(*this);
+}
+
+TokenList SqliteRollback::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("ROLLBACK").withSpace();
+ if (transactionKw)
+ builder.withKeyword("TRANSACTION").withSpace();
+
+ if (!name.isNull())
+ {
+ builder.withKeyword("TO").withSpace();
+ if (savepointKw)
+ builder.withKeyword("SAVEPOINT").withSpace();
+
+ builder.withOther(name, dialect);
+ }
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.h
new file mode 100644
index 0000000..1dc1574
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliterollback.h
@@ -0,0 +1,28 @@
+#ifndef SQLITEROLLBACK_H
+#define SQLITEROLLBACK_H
+
+#include "sqlitequery.h"
+#include <QString>
+
+class API_EXPORT SqliteRollback : public SqliteQuery
+{
+ public:
+ SqliteRollback();
+ SqliteRollback(const SqliteRollback& other);
+ SqliteRollback(bool transactionKw, const QString& name);
+ SqliteRollback(bool transactionKw, bool savePoint, const QString& name);
+
+ SqliteStatement* clone();
+
+ bool transactionKw = false;
+ bool toKw = false;
+ bool savepointKw = false;
+ QString name = QString::null;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteRollback> SqliteRollPtr;
+
+#endif // SQLITEROLLBACK_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.cpp
new file mode 100644
index 0000000..9003086
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.cpp
@@ -0,0 +1,32 @@
+#include "sqlitesavepoint.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteSavepoint::SqliteSavepoint()
+{
+ queryType = SqliteQueryType::Savepoint;
+}
+
+SqliteSavepoint::SqliteSavepoint(const SqliteSavepoint& other) :
+ SqliteQuery(other), name(other.name)
+{
+}
+
+SqliteSavepoint::SqliteSavepoint(const QString &name)
+ : SqliteSavepoint()
+{
+ this->name = name;
+}
+
+SqliteStatement*SqliteSavepoint::clone()
+{
+ return new SqliteSavepoint(*this);
+}
+
+TokenList SqliteSavepoint::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("SAVEPOINT").withSpace().withOther(name, dialect).withOperator(";");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.h
new file mode 100644
index 0000000..bd75c76
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesavepoint.h
@@ -0,0 +1,25 @@
+#ifndef SQLITESAVEPOINT_H
+#define SQLITESAVEPOINT_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+
+class API_EXPORT SqliteSavepoint : public SqliteQuery
+{
+ public:
+ SqliteSavepoint();
+ SqliteSavepoint(const SqliteSavepoint& other);
+ explicit SqliteSavepoint(const QString& name);
+
+ SqliteStatement* clone();
+
+ QString name = QString::null;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteSavepoint> SqliteSavepointPtr;
+
+#endif // SQLITESAVEPOINT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp
new file mode 100644
index 0000000..5452795
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.cpp
@@ -0,0 +1,783 @@
+#include "sqliteselect.h"
+#include "sqlitequerytype.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+#include "sqlitewith.h"
+#include <QSet>
+
+SqliteSelect::SqliteSelect()
+{
+ queryType = SqliteQueryType::Select;
+}
+
+SqliteSelect::SqliteSelect(const SqliteSelect& other) :
+ SqliteQuery(other)
+{
+ DEEP_COPY_COLLECTION(Core, coreSelects);
+ DEEP_COPY_FIELD(SqliteWith, with);
+}
+
+SqliteSelect* SqliteSelect::append(Core* core)
+{
+ SqliteSelect* select = new SqliteSelect();
+ select->coreSelects << core;
+ core->setParent(select);
+ return select;
+}
+
+SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundOperator op, Core* core)
+{
+ if (!select)
+ select = new SqliteSelect();
+
+ core->compoundOp = op;
+ select->coreSelects << core;
+ core->setParent(select);
+ return select;
+}
+
+SqliteSelect* SqliteSelect::append(const QList<QList<SqliteExpr*>>& values)
+{
+ return append(nullptr, CompoundOperator::null, values);
+}
+
+SqliteSelect* SqliteSelect::append(SqliteSelect* select, SqliteSelect::CompoundOperator op, const QList<QList<SqliteExpr*>>& values)
+{
+ if (!select)
+ select = new SqliteSelect();
+
+ bool first = true;
+
+ Core::ResultColumn* resCol = nullptr;
+ QList<Core::ResultColumn*> resColList;
+ foreach (const QList<SqliteExpr*>& singleValues, values)
+ {
+ Core* core = new Core();
+ core->setParent(select);
+ core->compoundOp = op;
+ core->valuesMode = true;
+ if (first)
+ {
+ op = CompoundOperator::UNION_ALL;
+ first = false;
+ }
+ select->coreSelects << core;
+
+ resColList.clear();
+ foreach (SqliteExpr* value, singleValues)
+ {
+ resCol = new Core::ResultColumn(value, false, QString::null);
+ resCol->rebuildTokens();
+ resCol->setParent(core);
+ core->resultColumns << resCol;
+ }
+ }
+
+ return select;
+}
+
+SqliteStatement*SqliteSelect::clone()
+{
+ return new SqliteSelect(*this);
+}
+
+QString SqliteSelect::compoundOperator(SqliteSelect::CompoundOperator op)
+{
+ switch (op)
+ {
+ case SqliteSelect::CompoundOperator::UNION:
+ return "UNION";
+ case SqliteSelect::CompoundOperator::UNION_ALL:
+ return "UNION ALL";
+ case SqliteSelect::CompoundOperator::INTERSECT:
+ return "INTERSECT";
+ case SqliteSelect::CompoundOperator::EXCEPT:
+ return "EXCEPT";
+ case SqliteSelect::CompoundOperator::null:
+ break;
+ }
+ return QString::null;
+}
+
+SqliteSelect::CompoundOperator SqliteSelect::compoundOperator(const QString& op)
+{
+ QString upStr = op.toUpper();
+ if (upStr == "UNION")
+ return CompoundOperator::UNION;
+ else if (upStr == "UNION ALL")
+ return CompoundOperator::UNION_ALL;
+ else if (upStr == "EXCEPT")
+ return CompoundOperator::EXCEPT;
+ else if (upStr == "INTERSECT")
+ return CompoundOperator::INTERSECT;
+ else
+ return CompoundOperator::null;
+}
+
+void SqliteSelect::reset()
+{
+ foreach (Core* core, coreSelects)
+ delete core;
+
+ coreSelects.clear();
+}
+
+void SqliteSelect::setWith(SqliteWith* with)
+{
+ this->with = with;
+ if (with)
+ with->setParent(this);
+}
+
+SqliteSelect::Core::Core()
+{
+}
+
+SqliteSelect::Core::Core(const SqliteSelect::Core& other) :
+ SqliteStatement(other), compoundOp(other.compoundOp), distinctKw(other.distinctKw), allKw(other.allKw)
+{
+ DEEP_COPY_COLLECTION(ResultColumn, resultColumns);
+ DEEP_COPY_FIELD(JoinSource, from);
+ DEEP_COPY_FIELD(SqliteExpr, where);
+ DEEP_COPY_FIELD(SqliteExpr, having);
+ DEEP_COPY_COLLECTION(SqliteExpr, groupBy);
+ DEEP_COPY_COLLECTION(SqliteOrderBy, orderBy);
+ DEEP_COPY_FIELD(SqliteLimit, limit);
+}
+
+SqliteSelect::Core::Core(int distinct, const QList<ResultColumn *> &resCols, SqliteSelect::Core::JoinSource *src, SqliteExpr *where, const QList<SqliteExpr *> &groupBy, SqliteExpr *having, const QList<SqliteOrderBy*>& orderBy, SqliteLimit* limit)
+{
+ if (distinct == 1)
+ distinctKw = true;
+ else if (distinct == 2)
+ allKw = true;
+
+ from = src;
+ this->where = where;
+ this->having = having;
+ this->groupBy = groupBy;
+ resultColumns = resCols;
+ this->limit = limit;
+ this->orderBy = orderBy;
+
+ if (from)
+ from->setParent(this);
+
+ if (where)
+ where->setParent(this);
+
+ if (having)
+ having->setParent(this);
+
+ if (limit)
+ limit->setParent(this);
+
+ foreach (SqliteOrderBy* order, orderBy)
+ order->setParent(this);
+
+ foreach (SqliteExpr* expr, groupBy)
+ expr->setParent(this);
+
+ foreach (SqliteSelect::Core::ResultColumn* resCol, resCols)
+ resCol->setParent(this);
+}
+
+SqliteStatement*SqliteSelect::Core::clone()
+{
+ return new SqliteSelect::Core(*this);
+}
+
+SqliteSelect::Core::ResultColumn::ResultColumn()
+{
+}
+
+SqliteSelect::Core::ResultColumn::ResultColumn(const SqliteSelect::Core::ResultColumn& other) :
+ SqliteStatement(other), star(other.star), asKw(other.asKw), alias(other.alias), table(other.table)
+{
+ DEEP_COPY_FIELD(SqliteExpr, expr);
+}
+
+SqliteSelect::Core::ResultColumn::ResultColumn(SqliteExpr *expr, bool asKw, const QString &alias)
+{
+ this->expr = expr;
+ this->asKw = asKw;
+ this->alias = alias;
+ if (expr)
+ expr->setParent(this);
+}
+
+SqliteSelect::Core::ResultColumn::ResultColumn(bool star, const QString &table)
+{
+ this->star = star;
+ this->table = table;
+}
+
+SqliteSelect::Core::ResultColumn::ResultColumn(bool star)
+{
+ this->star = star;
+}
+
+bool SqliteSelect::Core::ResultColumn::isRowId()
+{
+ if (!expr)
+ return false;
+
+ if (expr->column.isEmpty())
+ return false;
+
+ return expr->column.compare("rowid", Qt::CaseInsensitive) == 0;
+}
+
+SqliteStatement*SqliteSelect::Core::ResultColumn::clone()
+{
+ return new SqliteSelect::Core::ResultColumn(*this);
+}
+
+QStringList SqliteSelect::Core::ResultColumn::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+TokenList SqliteSelect::Core::ResultColumn::getTableTokensInStatement()
+{
+ // To avoid warnings about missing "nm" key
+ if (table.isNull())
+ return TokenList();
+
+ // Now, we know table was specified
+ return getTokenListFromNamedKey("nm");
+}
+
+QList<SqliteStatement::FullObject> SqliteSelect::Core::ResultColumn::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ TokenList tableTokens = getTableTokensInStatement();
+ FullObject fullObj;
+ if (tableTokens.size() > 0)
+ fullObj = getFullObject(FullObject::TABLE, dbTokenForFullObjects, tableTokens[0]);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+SqliteSelect::Core::SingleSource::SingleSource()
+{
+}
+
+SqliteSelect::Core::SingleSource::SingleSource(const SqliteSelect::Core::SingleSource& other) :
+ SqliteStatement(other), database(other.database), table(other.table), alias(other.alias), asKw(other.asKw), indexedByKw(other.indexedByKw),
+ notIndexedKw(other.notIndexedKw), indexedBy(other.indexedBy)
+{
+ DEEP_COPY_FIELD(SqliteSelect, select);
+ DEEP_COPY_FIELD(JoinSource, joinSource);
+}
+
+SqliteSelect::Core::SingleSource::SingleSource(const QString& name1, const QString& name2, bool asKw, const QString& alias, bool notIndexedKw, const QString& indexedBy)
+{
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+
+ this->asKw = asKw;
+ this->alias = alias;
+ this->indexedBy = indexedBy;
+ this->indexedByKw = !(indexedBy.isNull());
+ this->notIndexedKw = notIndexedKw;
+}
+
+SqliteSelect::Core::SingleSource::SingleSource(SqliteSelect *select, bool asKw, const QString &alias)
+{
+ this->select = select;
+ this->asKw = asKw;
+ this-> alias = alias;
+ if (select)
+ select->setParent(this);
+}
+
+SqliteSelect::Core::SingleSource::SingleSource(JoinSource *src, bool asKw, const QString &alias)
+{
+ this->joinSource = src;
+ this->asKw = asKw;
+ this-> alias = alias;
+ if (src)
+ src->setParent(this);
+}
+
+SqliteStatement*SqliteSelect::Core::SingleSource::clone()
+{
+ return new SqliteSelect::Core::SingleSource(*this);
+}
+
+QStringList SqliteSelect::Core::SingleSource::getTablesInStatement()
+{
+ // This method returns tables only! No aliases.
+ // Otherwise the completion sorter won't work correctly.
+ // To return tables with aliases use/create other method.
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteSelect::Core::SingleSource::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteSelect::Core::SingleSource::getTableTokensInStatement()
+{
+ if (table.isNull())
+ return TokenList();
+
+ return getObjectTokenListFromNmDbnm();
+}
+
+TokenList SqliteSelect::Core::SingleSource::getDatabaseTokensInStatement()
+{
+ if (database.isNull())
+ return TokenList();
+
+ return getDbTokenListFromNmDbnm();
+}
+
+QList<SqliteStatement::FullObject> SqliteSelect::Core::SingleSource::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Table object
+ if (!table.isNull())
+ {
+ FullObject fullObj = getFullObjectFromNmDbnm(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+ }
+
+ // Db object
+ if (!database.isNull())
+ {
+ FullObject fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+ }
+
+ return result;
+}
+
+SqliteSelect::Core::JoinConstraint::JoinConstraint()
+{
+}
+
+SqliteSelect::Core::JoinConstraint::JoinConstraint(const SqliteSelect::Core::JoinConstraint& other) :
+ SqliteStatement(other), columnNames(other.columnNames)
+{
+ DEEP_COPY_FIELD(SqliteExpr, expr);
+}
+
+SqliteSelect::Core::JoinConstraint::JoinConstraint(SqliteExpr *expr)
+{
+ this->expr = expr;
+ if (expr)
+ expr->setParent(this);
+}
+
+SqliteSelect::Core::JoinConstraint::JoinConstraint(const QList<QString> &strList)
+{
+ columnNames = strList;
+}
+
+SqliteStatement*SqliteSelect::Core::JoinConstraint::clone()
+{
+ return new SqliteSelect::Core::JoinConstraint(*this);
+}
+
+QStringList SqliteSelect::Core::JoinConstraint::getColumnsInStatement()
+{
+ QStringList list;
+ list += columnNames;
+ return list;
+}
+
+TokenList SqliteSelect::Core::JoinConstraint::getColumnTokensInStatement()
+{
+ TokenList list;
+ foreach (TokenPtr token, getTokenListFromNamedKey("inscollist", -1))
+ {
+ if (token->type == Token::OPERATOR) // a COMMA
+ continue;
+
+ list << token;
+ }
+ return list;
+}
+
+SqliteSelect::Core::JoinOp::JoinOp()
+{
+}
+
+SqliteSelect::Core::JoinOp::JoinOp(const SqliteSelect::Core::JoinOp& other) :
+ SqliteStatement(other), comma(other.comma), joinKw(other.joinKw), naturalKw(other.naturalKw), leftKw(other.leftKw), outerKw(other.outerKw),
+ innerKw(other.innerKw), crossKw(other.crossKw), rightKw(other.rightKw), fullKw(other.fullKw), customKw1(other.customKw1),
+ customKw2(other.customKw2), customKw3(other.customKw3)
+{
+}
+
+SqliteSelect::Core::JoinOp::JoinOp(bool comma)
+{
+ this->comma = comma;
+ this->joinKw = !comma;
+}
+
+SqliteSelect::Core::JoinOp::JoinOp(const QString &joinToken)
+{
+ this->joinKw = true;
+ init(joinToken);
+}
+
+SqliteSelect::Core::JoinOp::JoinOp(const QString &joinToken, const QString &word1)
+{
+ this->joinKw = true;
+ init(joinToken);
+ init(word1);
+}
+
+SqliteSelect::Core::JoinOp::JoinOp(const QString &joinToken, const QString &word1, const QString &word2)
+{
+ this->joinKw = true;
+ init(joinToken);
+ init(word1);
+ init(word2);
+}
+
+SqliteStatement*SqliteSelect::Core::JoinOp::clone()
+{
+ return new SqliteSelect::Core::JoinOp(*this);
+}
+
+void SqliteSelect::Core::JoinOp::init(const QString &str)
+{
+ QString upStr = str.toUpper();
+ if (upStr == "NATURAL")
+ naturalKw = true;
+ else if (upStr == "LEFT")
+ leftKw = true;
+ else if (upStr == "RIGHT")
+ rightKw = true;
+ else if (upStr == "FULL")
+ fullKw = true;
+ else if (upStr == "OUTER")
+ outerKw = true;
+ else if (upStr == "INNER")
+ innerKw = true;
+ else if (upStr == "CROSS")
+ crossKw = true;
+ else if (customKw1.isNull())
+ customKw1 = str;
+ else if (customKw2.isNull())
+ customKw2 = str;
+ else
+ customKw3 = str;
+}
+
+
+SqliteSelect::Core::JoinSourceOther::JoinSourceOther()
+{
+}
+
+SqliteSelect::Core::JoinSourceOther::JoinSourceOther(const SqliteSelect::Core::JoinSourceOther& other) :
+ SqliteStatement(other)
+{
+ DEEP_COPY_FIELD(JoinOp, joinOp);
+ DEEP_COPY_FIELD(SingleSource, singleSource);
+ DEEP_COPY_FIELD(JoinConstraint, joinConstraint);
+}
+
+SqliteSelect::Core::JoinSourceOther::JoinSourceOther(SqliteSelect::Core::JoinOp *op, SingleSource *src, JoinConstraint *constr)
+{
+ this->joinConstraint = constr;
+ this->joinOp = op;
+ this->singleSource = src;
+ if (constr)
+ constr->setParent(this);
+
+ if (op)
+ op->setParent(this);
+
+ if (src)
+ src->setParent(this);
+}
+
+SqliteStatement*SqliteSelect::Core::JoinSourceOther::clone()
+{
+ return new SqliteSelect::Core::JoinSourceOther(*this);
+}
+
+
+SqliteSelect::Core::JoinSource::JoinSource()
+{
+}
+
+SqliteSelect::Core::JoinSource::JoinSource(const JoinSource& other) :
+ SqliteStatement(other)
+{
+ DEEP_COPY_FIELD(SingleSource, singleSource);
+ DEEP_COPY_COLLECTION(JoinSourceOther, otherSources);
+}
+
+SqliteSelect::Core::JoinSource::JoinSource(SqliteSelect::Core::SingleSource *singleSource, const QList<SqliteSelect::Core::JoinSourceOther *> &list)
+{
+ this->singleSource = singleSource;
+ this->otherSources = list;
+ if (singleSource)
+ singleSource->setParent(this);
+
+ foreach (JoinSourceOther* other, otherSources)
+ other->setParent(this);
+}
+
+SqliteStatement*SqliteSelect::Core::JoinSource::clone()
+{
+ return new SqliteSelect::Core::JoinSource(*this);
+}
+
+
+TokenList SqliteSelect::Core::ResultColumn::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (star)
+ {
+ if (!table.isNull())
+ builder.withOther(table, dialect).withOperator(".");
+
+ builder.withOperator("*");
+ }
+ else
+ {
+ builder.withStatement(expr);
+ if (!alias.isNull())
+ {
+ if (asKw)
+ builder.withSpace().withKeyword("AS");
+
+ builder.withSpace().withOther(alias, dialect);
+ }
+ }
+
+ return builder.build();
+}
+
+TokenList SqliteSelect::Core::SingleSource::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (!table.isNull())
+ {
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect);
+
+ 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)
+ {
+ builder.withParLeft().withStatement(select).withParRight();
+ if (!alias.isNull())
+ {
+ if (asKw)
+ builder.withSpace().withKeyword("AS");
+
+ builder.withSpace().withOther(alias, dialect);
+ }
+ }
+ else
+ {
+ builder.withParLeft().withStatement(joinSource).withParRight();
+ }
+
+ return builder.build();
+}
+
+TokenList SqliteSelect::Core::JoinOp::rebuildTokensFromContents()
+{
+ switch (dialect)
+ {
+ case Dialect::Sqlite3:
+ return rebuildTokensForSqlite2();
+ case Dialect::Sqlite2:
+ return rebuildTokensForSqlite3();
+ }
+ return TokenList();
+}
+
+TokenList SqliteSelect::Core::JoinOp::rebuildTokensForSqlite2()
+{
+ StatementTokenBuilder builder;
+ if (comma)
+ {
+ builder.withOperator(",");
+ }
+ else
+ {
+ if (naturalKw)
+ builder.withKeyword("NATURAL").withSpace();
+
+ if (leftKw)
+ builder.withKeyword("LEFT").withSpace();
+ else if (rightKw)
+ builder.withKeyword("RIGHT").withSpace();
+ else if (fullKw)
+ builder.withKeyword("FULL").withSpace();
+
+ if (innerKw)
+ builder.withKeyword("INNER").withSpace();
+ else if (crossKw)
+ builder.withKeyword("CROSS").withSpace();
+ else if (outerKw)
+ builder.withKeyword("OUTER").withSpace();
+
+ builder.withKeyword("JOIN");
+ }
+
+ return builder.build();
+}
+
+TokenList SqliteSelect::Core::JoinOp::rebuildTokensForSqlite3()
+{
+ StatementTokenBuilder builder;
+ if (comma)
+ {
+ builder.withOperator(",");
+ }
+ else
+ {
+ if (naturalKw)
+ builder.withKeyword("NATURAL").withSpace();
+
+ if (leftKw)
+ {
+ builder.withKeyword("LEFT").withSpace();
+ if (outerKw)
+ builder.withKeyword("OUTER").withSpace();
+ }
+ else if (innerKw)
+ builder.withKeyword("INNER").withSpace();
+ else if (crossKw)
+ builder.withKeyword("CROSS").withSpace();
+
+ builder.withKeyword("JOIN");
+ }
+
+ return builder.build();
+}
+
+
+TokenList SqliteSelect::Core::JoinConstraint::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (expr)
+ builder.withKeyword("ON").withStatement(expr);
+ else
+ builder.withKeyword("USING").withSpace().withParLeft().withOtherList(columnNames, dialect).withParRight();
+
+ return builder.build();
+}
+
+
+TokenList SqliteSelect::Core::JoinSourceOther::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(joinOp).withStatement(singleSource).withStatement(joinConstraint);
+ return builder.build();
+}
+
+
+TokenList SqliteSelect::Core::JoinSource::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withStatement(singleSource).withStatementList(otherSources, "");
+ return builder.build();
+}
+
+
+TokenList SqliteSelect::Core::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (valuesMode)
+ {
+ builder.withKeyword("VALUES").withSpace().withParLeft().withStatementList(resultColumns).withParRight();
+ return builder.build();
+ }
+
+ builder.withKeyword("SELECT");
+ if (distinctKw)
+ builder.withSpace().withKeyword("DISTINCT");
+ else if (allKw)
+ builder.withSpace().withKeyword("ALL");
+
+ builder.withStatementList(resultColumns);
+ if (from)
+ builder.withSpace().withKeyword("FROM").withStatement(from);
+
+ if (where)
+ builder.withSpace().withKeyword("WHERE").withStatement(where);
+
+ if (groupBy.size() > 0)
+ {
+ builder.withSpace().withKeyword("GROUP").withSpace().withKeyword("BY").withStatementList(groupBy);
+ if (having)
+ builder.withSpace().withKeyword("HAVING").withStatement(having);
+ }
+
+ if (orderBy.size() > 0)
+ builder.withSpace().withKeyword("ORDER").withSpace().withKeyword("BY").withStatementList(orderBy);
+
+ if (limit)
+ builder.withStatement(limit);
+
+ return builder.build();
+}
+
+TokenList SqliteSelect::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ if (with)
+ builder.withStatement(with);
+
+ foreach (SqliteSelect::Core* core, coreSelects)
+ {
+ if (core->compoundOp == CompoundOperator::UNION_ALL)
+ {
+ if (core->valuesMode)
+ builder.withSpace().withOperator(",");
+ else
+ builder.withSpace().withKeyword("UNION").withSpace().withKeyword("ALL");
+ }
+ else if (core->compoundOp != CompoundOperator::null)
+ builder.withSpace().withKeyword(compoundOperator(core->compoundOp));
+
+ builder.withStatement(core);
+ }
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h
new file mode 100644
index 0000000..22d1921
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteselect.h
@@ -0,0 +1,228 @@
+#ifndef SQLITESELECT_H
+#define SQLITESELECT_H
+
+#include "sqlitequery.h"
+#include "sqliteexpr.h"
+#include "sqlitelimit.h"
+#include "sqliteorderby.h"
+
+#include <QList>
+
+class SqliteWith;
+
+/**
+ * @addtogroup sqlite_statement
+ * @brief The SqliteSelect class
+ */
+class API_EXPORT SqliteSelect : public SqliteQuery
+{
+ public:
+ enum class CompoundOperator
+ {
+ UNION,
+ UNION_ALL,
+ INTERSECT,
+ EXCEPT,
+ null
+ };
+
+ class API_EXPORT Core : public SqliteStatement
+ {
+ public:
+ class API_EXPORT ResultColumn : public SqliteStatement
+ {
+ public:
+ ResultColumn();
+ ResultColumn(const ResultColumn& other);
+ ResultColumn(SqliteExpr* expr, bool asKw, const QString& alias);
+ ResultColumn(bool star, const QString& table);
+ explicit ResultColumn(bool star);
+
+ bool isRowId();
+ SqliteStatement* clone();
+
+ SqliteExpr* expr = nullptr;
+ bool star = false;
+ bool asKw = false;
+ QString alias = QString::null;
+ QString table = QString::null;
+
+ protected:
+ QStringList getTablesInStatement();
+ TokenList getTableTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+ };
+
+ class JoinSource; // forward declaration
+
+ class API_EXPORT SingleSource : public SqliteStatement
+ {
+ public:
+ SingleSource();
+ SingleSource(const SingleSource& other);
+ SingleSource(const QString& name1, const QString& name2,
+ bool asKw, const QString& alias, bool notIndexedKw, const QString& indexedBy);
+ SingleSource(SqliteSelect* select, bool asKw, const QString& alias);
+ SingleSource(JoinSource* src, bool asKw, const QString& alias);
+
+ SqliteStatement* clone();
+
+ QString database = QString::null;
+ QString table = QString::null;
+ QString alias = QString::null;
+ bool asKw = false;
+ bool indexedByKw = false;
+ bool notIndexedKw = false;
+ QString indexedBy = QString::null;
+ SqliteSelect* select = nullptr;
+ JoinSource* joinSource = nullptr;
+
+ protected:
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+ };
+
+ class API_EXPORT JoinOp : public SqliteStatement
+ {
+ public:
+ JoinOp();
+ JoinOp(const JoinOp& other);
+ explicit JoinOp(bool comma);
+ explicit JoinOp(const QString& joinToken);
+ JoinOp(const QString& joinToken, const QString& word1);
+ JoinOp(const QString& joinToken, const QString& word1, const QString& word2);
+
+ SqliteStatement* clone();
+
+ private:
+ void init(const QString& str);
+
+ public:
+ bool comma = false;
+ bool joinKw = false;
+ bool naturalKw = false;
+ bool leftKw = false;
+ bool outerKw = false;
+ bool innerKw = false;
+ bool crossKw = false;
+ bool rightKw = false;
+ bool fullKw = false;
+ QString customKw1 = QString::null;
+ QString customKw2 = QString::null;
+ QString customKw3 = QString::null;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+
+ private:
+ TokenList rebuildTokensForSqlite2();
+ TokenList rebuildTokensForSqlite3();
+ };
+
+ class API_EXPORT JoinConstraint : public SqliteStatement
+ {
+ public:
+ JoinConstraint();
+ JoinConstraint(const JoinConstraint& other);
+ explicit JoinConstraint(SqliteExpr* expr);
+ explicit JoinConstraint(const QList<QString>& strList);
+
+ SqliteStatement* clone();
+
+ SqliteExpr* expr = nullptr;
+ QList<QString> columnNames;
+
+ protected:
+ QStringList getColumnsInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList rebuildTokensFromContents();
+ };
+
+ class API_EXPORT JoinSourceOther : public SqliteStatement
+ {
+ public:
+ JoinSourceOther();
+ JoinSourceOther(const JoinSourceOther& other);
+ JoinSourceOther(SqliteSelect::Core::JoinOp *op,
+ SqliteSelect::Core::SingleSource* src,
+ SqliteSelect::Core::JoinConstraint* constr);
+
+ SqliteStatement* clone();
+
+ JoinOp* joinOp = nullptr;
+ SingleSource* singleSource = nullptr;
+ JoinConstraint* joinConstraint = nullptr;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ class API_EXPORT JoinSource : public SqliteStatement
+ {
+ public:
+ JoinSource();
+ JoinSource(const JoinSource& other);
+ JoinSource(SingleSource* singleSource, const QList<JoinSourceOther*>& list);
+
+ SqliteStatement* clone();
+
+ SingleSource* singleSource = nullptr;
+ QList<JoinSourceOther*> otherSources;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ Core();
+ Core(const Core& other);
+ Core(int distinct, const QList<ResultColumn*>& resCols, JoinSource* src, SqliteExpr* where,
+ const QList<SqliteExpr*>& groupBy, SqliteExpr* having, const QList<SqliteOrderBy*>& orderBy,
+ SqliteLimit* limit);
+
+ SqliteStatement* clone();
+
+ CompoundOperator compoundOp = CompoundOperator::null;
+ QList<ResultColumn*> resultColumns;
+ JoinSource* from = nullptr;
+ bool distinctKw = false;
+ bool allKw = false;
+ SqliteExpr* where = nullptr;
+ SqliteExpr* having = nullptr;
+ QList<SqliteExpr*> groupBy;
+ QList<SqliteOrderBy*> orderBy;
+ SqliteLimit* limit = nullptr;
+ bool valuesMode = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ SqliteSelect();
+ SqliteSelect(const SqliteSelect& other);
+
+ static SqliteSelect* append(SqliteSelect::Core* core);
+ static SqliteSelect* append(SqliteSelect* select, CompoundOperator op, SqliteSelect::Core* core);
+ static SqliteSelect* append(const QList<QList<SqliteExpr*>>& values);
+ static SqliteSelect* append(SqliteSelect* select, SqliteSelect::CompoundOperator op, const QList<QList<SqliteExpr*>>& values);
+
+ SqliteStatement* clone();
+ QString compoundOperator(CompoundOperator op);
+ CompoundOperator compoundOperator(const QString& op);
+ void reset();
+ void setWith(SqliteWith* with);
+
+ QList<Core*> coreSelects;
+ SqliteWith* with = nullptr;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteSelect> SqliteSelectPtr;
+
+#endif // SQLITESELECT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.cpp
new file mode 100644
index 0000000..13f3951
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.cpp
@@ -0,0 +1,25 @@
+#include "sqlitesortorder.h"
+
+SqliteSortOrder sqliteSortOrder(const QString& value)
+{
+ if (value == "ASC")
+ return SqliteSortOrder::ASC;
+ else if (value == "DESC")
+ return SqliteSortOrder::DESC;
+ else
+ return SqliteSortOrder::null;
+}
+
+QString sqliteSortOrder(SqliteSortOrder value)
+{
+ switch (value)
+ {
+ case SqliteSortOrder::ASC:
+ return "ASC";
+ case SqliteSortOrder::DESC:
+ return "DESC";
+ default:
+ return QString::null;
+
+ }
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.h
new file mode 100644
index 0000000..51c7052
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitesortorder.h
@@ -0,0 +1,17 @@
+#ifndef SQLITESORTORDER_H
+#define SQLITESORTORDER_H
+
+#include "coreSQLiteStudio_global.h"
+#include <QString>
+
+enum class SqliteSortOrder
+{
+ ASC,
+ DESC,
+ null
+};
+
+API_EXPORT SqliteSortOrder sqliteSortOrder(const QString& value);
+API_EXPORT QString sqliteSortOrder(SqliteSortOrder value);
+
+#endif // SQLITESORTORDER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp
new file mode 100644
index 0000000..482baf8
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.cpp
@@ -0,0 +1,553 @@
+#include "sqlitestatement.h"
+#include "../token.h"
+#include "../lexer.h"
+#include "common/unused.h"
+#include <QDebug>
+
+SqliteStatement::SqliteStatement()
+{
+}
+
+SqliteStatement::SqliteStatement(const SqliteStatement& other) :
+ QObject(), tokens(other.tokens), tokensMap(other.tokensMap), dialect(other.dialect)
+{
+
+}
+
+SqliteStatement::~SqliteStatement()
+{
+}
+
+QString SqliteStatement::detokenize()
+{
+ return tokens.detokenize();
+}
+
+QStringList SqliteStatement::getContextColumns(bool checkParent, bool checkChilds)
+{
+ return getContextColumns(this, checkParent, checkChilds);
+}
+
+QStringList SqliteStatement::getContextTables(bool checkParent, bool checkChilds)
+{
+ return getContextTables(this, checkParent, checkChilds);
+}
+
+QStringList SqliteStatement::getContextDatabases(bool checkParent, bool checkChilds)
+{
+ return getContextDatabases(this, checkParent, checkChilds);
+}
+
+TokenList SqliteStatement::getContextColumnTokens(bool checkParent, bool checkChilds)
+{
+ return getContextColumnTokens(this, checkParent, checkChilds);
+}
+
+TokenList SqliteStatement::getContextTableTokens(bool checkParent, bool checkChilds)
+{
+ return getContextTableTokens(this, checkParent, checkChilds);
+}
+
+TokenList SqliteStatement::getContextDatabaseTokens(bool checkParent, bool checkChilds)
+{
+ return getContextDatabaseTokens(this, checkParent, checkChilds);
+}
+
+QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(bool checkParent, bool checkChilds)
+{
+ QList<FullObject> fullObjects = getContextFullObjects(this, checkParent, checkChilds);
+
+ FullObject fullObj;
+ QMutableListIterator<FullObject> it(fullObjects);
+ while (it.hasNext())
+ {
+ fullObj = it.next();
+ if (fullObj.type == SqliteStatement::FullObject::NONE)
+ {
+ qWarning() << "FullObject of type NONE!";
+ it.remove();
+ continue;
+ }
+
+ if (fullObj.type != SqliteStatement::FullObject::DATABASE && !fullObj.object)
+ {
+ qWarning() << "No 'object' member in FullObject that is not of DATABASE type!";
+ it.remove();
+ continue;
+ }
+
+ if (fullObj.type == SqliteStatement::FullObject::DATABASE && !fullObj.database)
+ {
+ qWarning() << "No 'database' member in FullObject that is of DATABASE type!";
+ it.remove();
+ continue;
+ }
+ }
+
+ return fullObjects;
+}
+
+void SqliteStatement::setSqliteDialect(Dialect dialect)
+{
+ this->dialect = dialect;
+ foreach (SqliteStatement* stmt, childStatements())
+ stmt->setSqliteDialect(dialect);
+}
+
+SqliteStatementPtr SqliteStatement::detach()
+{
+ if (!parent())
+ qWarning() << "Detaching " << this << ", but there's no parent!";
+
+ setParent(nullptr);
+ return SqliteStatementPtr(this);
+}
+
+void SqliteStatement::processPostParsing()
+{
+ evaluatePostParsing();
+ foreach (SqliteStatement* stmt, childStatements())
+ stmt->processPostParsing();
+}
+
+QStringList SqliteStatement::getContextColumns(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ QStringList results = getColumnsInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextColumns(this, checkParent, checkChilds);
+
+ return results;
+}
+
+QStringList SqliteStatement::getContextTables(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ QStringList results = getTablesInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextTables(this, checkParent, checkChilds);
+
+ return results;
+}
+
+QStringList SqliteStatement::getContextDatabases(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ QStringList results = getDatabasesInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextDatabases(this, checkParent, checkChilds);
+
+ return results;
+}
+
+TokenList SqliteStatement::getContextColumnTokens(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ TokenList results = getColumnTokensInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextColumnTokens(this, checkParent, checkChilds);
+
+ return results;
+}
+
+TokenList SqliteStatement::getContextTableTokens(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ TokenList results = getTableTokensInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextTableTokens(this, checkParent, checkChilds);
+
+ return results;
+}
+
+TokenList SqliteStatement::getContextDatabaseTokens(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ TokenList results = getDatabaseTokensInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ results += stmt->getContextDatabaseTokens(this, checkParent, checkChilds);
+
+ return results;
+}
+
+QList<SqliteStatement::FullObject> SqliteStatement::getContextFullObjects(SqliteStatement* caller, bool checkParent, bool checkChilds)
+{
+ QList<SqliteStatement::FullObject> results = getFullObjectsInStatement();
+ foreach (SqliteStatement* stmt, getContextStatements(caller, checkParent, checkChilds))
+ {
+ stmt->setContextDbForFullObject(dbTokenForFullObjects);
+ results += stmt->getContextFullObjects(this, checkParent, checkChilds);
+ }
+
+ return results;
+}
+
+QStringList SqliteStatement::getColumnsInStatement()
+{
+ return QStringList();
+}
+
+QStringList SqliteStatement::getTablesInStatement()
+{
+ return QStringList();
+}
+
+QStringList SqliteStatement::getDatabasesInStatement()
+{
+ return QStringList();
+}
+
+TokenList SqliteStatement::getColumnTokensInStatement()
+{
+ return TokenList();
+}
+
+TokenList SqliteStatement::getTableTokensInStatement()
+{
+ return TokenList();
+}
+
+TokenList SqliteStatement::getDatabaseTokensInStatement()
+{
+ return TokenList();
+}
+
+QList<SqliteStatement::FullObject> SqliteStatement::getFullObjectsInStatement()
+{
+ return QList<SqliteStatement::FullObject>();
+}
+
+TokenList SqliteStatement::rebuildTokensFromContents()
+{
+ qCritical() << "called rebuildTokensFromContents() for SqliteStatement that has no implementation for it.";
+ return TokenList();
+}
+
+void SqliteStatement::evaluatePostParsing()
+{
+}
+
+QList<SqliteStatement *> SqliteStatement::getContextStatements(SqliteStatement *caller, bool checkParent, bool checkChilds)
+{
+ QList<SqliteStatement *> results;
+
+ SqliteStatement* stmt = parentStatement();
+ if (checkParent && stmt && stmt != caller)
+ results += stmt;
+
+ if (checkChilds)
+ {
+ foreach (stmt, childStatements())
+ {
+ if (stmt == caller)
+ continue;
+
+ results += stmt;
+ }
+ }
+
+ return results;
+}
+
+TokenList SqliteStatement::extractPrintableTokens(const TokenList &tokens, bool skipMeaningless)
+{
+ TokenList list;
+ foreach (TokenPtr token, tokens)
+ {
+ switch (token->type)
+ {
+ case Token::OTHER:
+ case Token::STRING:
+ case Token::FLOAT:
+ case Token::INTEGER:
+ case Token::BIND_PARAM:
+ case Token::OPERATOR:
+ case Token::PAR_LEFT:
+ case Token::PAR_RIGHT:
+ case Token::BLOB:
+ case Token::KEYWORD:
+ list << token;
+ break;
+ case Token::COMMENT:
+ case Token::SPACE:
+ if (!skipMeaningless)
+ list << token;
+ break;
+ default:
+ break;
+ }
+ }
+ return list;
+}
+
+QStringList SqliteStatement::getStrListFromValue(const QString &value)
+{
+ QStringList list;
+ if (!value.isNull())
+ list << value;
+
+ return list;
+}
+
+TokenList SqliteStatement::getTokenListFromNamedKey(const QString &tokensMapKey, int idx)
+{
+ TokenList list;
+ if (tokensMap.contains(tokensMapKey))
+ {
+ if (idx < 0)
+ list += extractPrintableTokens(tokensMap[tokensMapKey]);
+ else if (tokensMap[tokensMapKey].size() > idx)
+ list << extractPrintableTokens(tokensMap[tokensMapKey])[idx];
+ }
+ else
+ qCritical() << "No '" << tokensMapKey << "' in tokens map when asked for it in getTokenListFromNamedKey().";
+
+ return list;
+}
+
+TokenPtr SqliteStatement::getDbTokenFromFullname(const QString &tokensMapKey)
+{
+ if (!tokensMap.contains(tokensMapKey))
+ {
+ qCritical() << "No '" << tokensMapKey << "' in tokens map when asked for it getDbTokenFromFullname().";
+ return TokenPtr();
+ }
+
+ TokenList tokens = extractPrintableTokens(tokensMap[tokensMapKey]);
+
+ if (tokens.size() == 3)
+ return tokens[0];
+ else if (tokens.size() == 1)
+ return TokenPtr();
+ else
+ qCritical() << "Expected 1 or 3 tokens in '" << tokensMapKey << "' in tokens map, but got" << tokens.size();
+
+ return TokenPtr();
+}
+
+TokenPtr SqliteStatement::getObjectTokenFromFullname(const QString &tokensMapKey)
+{
+ if (!tokensMap.contains(tokensMapKey))
+ {
+ qCritical() << "No '" << tokensMapKey << "' in tokens map when asked for it.";
+ return TokenPtr();
+ }
+
+ TokenList tokens = extractPrintableTokens(tokensMap[tokensMapKey]);
+ if (tokens.size() == 3)
+ return tokens[2];
+ else if (tokens.size() == 1)
+ return tokens[0];
+ else
+ qCritical() << "Expected 1 or 3 tokens in '" << tokensMapKey << "' in tokens map, but got" << tokens.size();
+
+ return TokenPtr();
+}
+
+TokenPtr SqliteStatement::getDbTokenFromNmDbnm(const QString &tokensMapKey1, const QString &tokensMapKey2)
+{
+ if (!tokensMap.contains(tokensMapKey1))
+ {
+ qCritical() << "No '" << tokensMapKey1 << "' in tokens map when asked for it in getDbTokenFromNmDbnm().";
+ return TokenPtr();
+ }
+
+ // It seems like checking tokensMapKey2 has no added value to the logic, while it prevents from reporting
+ // database token in case of: SELECT * FROM dbName. <- the valid query with "minor" error
+ UNUSED(tokensMapKey2);
+// if (!tokensMap.contains(tokensMapKey2))
+// {
+// qCritical() << "No '" << tokensMapKey2 << "' in tokens map when asked for it in getDbTokenFromNmDbnm().";
+// return TokenPtr();
+// }
+
+// if (tokensMap[tokensMapKey2].size() == 0)
+// return TokenPtr();
+
+ if (!tokensMap.contains("DOT") && tokensMap[tokensMapKey2].size() == 0)
+ {
+ // In this case the query is "SELECT * FROM test" and there is no database,
+ // but if there was a dot after the "test", then the "test" is a database name,
+ // so this block won't be executed. Instead the name of the database will be returned below.
+ return TokenPtr();
+ }
+
+ return extractPrintableTokens(tokensMap[tokensMapKey1])[0];
+}
+
+TokenPtr SqliteStatement::getObjectTokenFromNmDbnm(const QString &tokensMapKey1, const QString &tokensMapKey2)
+{
+ if (!tokensMap.contains(tokensMapKey1))
+ {
+ qCritical() << "No '" << tokensMapKey1 << "' in tokens map when asked for it in getObjectTokenFromNmDbnm().";
+ return TokenPtr();
+ }
+
+ if (!tokensMap.contains(tokensMapKey2))
+ {
+ qCritical() << "No '" << tokensMapKey2 << "' in tokens map when asked for it in getObjectTokenFromNmDbnm().";
+ return TokenPtr();
+ }
+
+ if (tokensMap[tokensMapKey2].size() == 0)
+ return extractPrintableTokens(tokensMap[tokensMapKey1])[0];
+
+ return extractPrintableTokens(tokensMap[tokensMapKey2])[1];
+}
+
+TokenList SqliteStatement::getDbTokenListFromFullname(const QString &tokensMapKey)
+{
+ TokenList list;
+ TokenPtr token = getDbTokenFromFullname(tokensMapKey);
+ if (token)
+ list << token;
+
+ return list;
+}
+
+TokenList SqliteStatement::getObjectTokenListFromFullname(const QString &tokensMapKey)
+{
+ TokenList list;
+ TokenPtr token = getObjectTokenFromFullname(tokensMapKey);
+ if (token)
+ list << token;
+
+ return list;
+}
+
+TokenList SqliteStatement::getDbTokenListFromNmDbnm(const QString &tokensMapKey1, const QString &tokensMapKey2)
+{
+ TokenList list;
+ TokenPtr token = getDbTokenFromNmDbnm(tokensMapKey1, tokensMapKey2);
+ if (token)
+ list << token;
+
+ return list;
+}
+
+TokenList SqliteStatement::getObjectTokenListFromNmDbnm(const QString &tokensMapKey1, const QString &tokensMapKey2)
+{
+ TokenList list;
+ TokenPtr token = getObjectTokenFromNmDbnm(tokensMapKey1, tokensMapKey2);
+ if (token)
+ list << token;
+
+ return list;
+}
+
+SqliteStatement::FullObject SqliteStatement::getFullObjectFromFullname(SqliteStatement::FullObject::Type type, const QString& tokensMapKey)
+{
+ return getFullObject(type, getDbTokenFromFullname(tokensMapKey), getObjectTokenFromFullname(tokensMapKey));
+}
+
+SqliteStatement::FullObject SqliteStatement::getFullObjectFromNmDbnm(SqliteStatement::FullObject::Type type, const QString& tokensMapKey1, const QString& tokensMapKey2)
+{
+ return getFullObject(type, getDbTokenFromNmDbnm(tokensMapKey1, tokensMapKey2), getObjectTokenFromNmDbnm(tokensMapKey1, tokensMapKey2));
+}
+
+SqliteStatement::FullObject SqliteStatement::getFullObject(SqliteStatement::FullObject::Type type, TokenPtr dbToken, TokenPtr objToken)
+{
+ FullObject fullObj;
+ if (!objToken)
+ return fullObj;
+
+ fullObj.database = dbToken;
+ fullObj.object = objToken;
+ fullObj.type = type;
+ return fullObj;
+}
+
+void SqliteStatement::setContextDbForFullObject(TokenPtr dbToken)
+{
+ dbTokenForFullObjects = dbToken;
+}
+
+SqliteStatement::FullObject SqliteStatement::getFirstDbFullObject()
+{
+ TokenList dbTokens = getDatabaseTokensInStatement();
+ return getDbFullObject(dbTokens.size() > 0 ? dbTokens[0] : TokenPtr());
+}
+
+SqliteStatement::FullObject SqliteStatement::getDbFullObject(TokenPtr dbToken)
+{
+ FullObject fullObj;
+ if (!dbToken)
+ return fullObj;
+
+ fullObj.database = dbToken;
+ fullObj.type = FullObject::DATABASE;
+ return fullObj;
+}
+
+Range SqliteStatement::getRange()
+{
+ if (tokens.size() == 0)
+ return Range(0, 0);
+
+ return Range(tokens.first()->start, tokens.last()->end);
+}
+
+SqliteStatement *SqliteStatement::findStatementWithToken(TokenPtr token)
+{
+ SqliteStatement* stmtWithToken = nullptr;
+ foreach (SqliteStatement* stmt, childStatements())
+ {
+ stmtWithToken = stmt->findStatementWithToken(token);
+ if (stmtWithToken)
+ return stmtWithToken;
+ }
+
+ if (tokens.contains(token))
+ return this;
+
+ return nullptr;
+}
+
+SqliteStatement *SqliteStatement::findStatementWithPosition(quint64 cursorPosition)
+{
+ TokenPtr token = tokens.atCursorPosition(cursorPosition);
+ if (!token)
+ return nullptr;
+
+ return findStatementWithToken(token);
+}
+
+SqliteStatement *SqliteStatement::parentStatement()
+{
+ if (!parent())
+ return nullptr;
+
+ return dynamic_cast<SqliteStatement*>(parent());
+}
+
+QList<SqliteStatement *> SqliteStatement::childStatements()
+{
+ QList<SqliteStatement*> results;
+ foreach (QObject* obj, children())
+ results += dynamic_cast<SqliteStatement*>(obj);
+
+ return results;
+}
+
+void SqliteStatement::rebuildTokens()
+{
+ tokens.clear();
+ tokensMap.clear();
+ tokens = rebuildTokensFromContents();
+ // TODO rebuild tokensMap as well
+ // It shouldn't be hard to write unit tests that parse a query, remembers it tokensMap, then rebuilds tokens from contents
+ // and then compare new tokens map with previous one. This way we should be able to get all maps correctly.
+}
+
+void SqliteStatement::setParent(QObject* parent)
+{
+ QObject::setParent(parent);
+ SqliteStatement* stmt = qobject_cast<SqliteStatement*>(parent);
+ if (stmt)
+ dialect = stmt->dialect;
+}
+
+void SqliteStatement::attach(SqliteStatement*& memberForChild, SqliteStatement* childStatementToAttach)
+{
+ memberForChild = childStatementToAttach;
+ childStatementToAttach->setParent(this);
+}
+
+bool SqliteStatement::FullObject::isValid() const
+{
+ return (object != nullptr || (type == DATABASE && database != nullptr));
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h
new file mode 100644
index 0000000..bacb2d7
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitestatement.h
@@ -0,0 +1,339 @@
+#ifndef SQLITESTATEMENT_H
+#define SQLITESTATEMENT_H
+
+#include "common/utils.h"
+#include "parser/token.h"
+#include "dialect.h"
+#include <QList>
+#include <QHash>
+#include <QObject>
+#include <QPair>
+#include <QStringList>
+#include <QSharedPointer>
+
+// TODO start using attach() in most cases where setParent() is used
+
+class SqliteStatement;
+typedef QSharedPointer<SqliteStatement> SqliteStatementPtr;
+
+/**
+ * @defgroup sqlite_statement Parser result containers
+ */
+
+/**
+ * @ingroup sqlite_statement
+ *
+ * @brief General container for any type of parsed object.
+ *
+ * Statements can have multiple children statements and single parent statement.
+ * This way they create a tree of objects. Since those statements represent various language
+ * statements (here SQL), such tree is also called an Abstract Syntax Tree (aka AST).
+ *
+ * The AST lets you to examine structure of the query in a logical manner.
+ * In other words, once you parse query into AST, you have a tree of object, where each oject in
+ * the tree represents some part of the query and provides all its parameters as member variables.
+ *
+ * Deleting single statement causes all it's children to be deleted automatically.
+ *
+ * @section output_from_parser SqliteStatement as output from Parser
+ *
+ * The SqliteStatement is the most generic representation of Parser processing results.
+ * Every parsed query is represented by its specialized, derived class, but it's also
+ * the SqliteQuery and every SqliteQuery is also the SqliteStatement.
+ *
+ * Apart from SqliteQuery objects, which represent complete SQLite queries, there are also
+ * other statements, like expressions (http://sqlite.org/lang_expr.html) and others.
+ * Those statements don't inherit from SqliteQuery, but directly from SqliteStatement.
+ *
+ * Every parsed statement contains list of tokens that were used to parse this statement
+ * in SqliteStatement::tokens.
+ *
+ * There is also SqliteStatement::tokensMap, which is a table mapping grammar rule name
+ * into tokens used to fulfill that rule. To learn possible keys for each SqliteStatement,
+ * you have to look into sqlite2.y and sqlite3.y files and see definition of the statement,
+ * that you're examining SqliteStatement::tokensMap for.
+ *
+ * @note SqliteStatement::tokensMap is a low level API and it's not very predictible,
+ * unless you get to know it very well. That's why it's not recommended to use it.
+ *
+ * Example of working with SqliteStatement::tokensMap: you have a SqliteAttachPtr from the parser.
+ * You can learn the "attach name" from SqliteAttach::name, like this:
+ * @code
+ * QString name;
+ * if (attachPtr->name)
+ * name = attachPtr->name->detokenize();
+ * @endcode
+ * or you can use tokensMap like this:
+ * @code
+ * QString name;
+ * if (attachPtr->tokensMap["expr2"])
+ * name = attachPtr->tokensMap["expr2"]->detokenize();
+ * @endcode
+ *
+ * Why using tokensMap, when you can read values from object member easly? Well, object members
+ * have plain values (string, integer, etc), while tokensMap has tokens, so you can examine
+ * at which character exactly was the value placed, where it ended, etc.
+ *
+ * @section query_generation SqliteStatement as utility for generating query string
+ *
+ * Generating query string with SqliteStatement makes sense only in case, when you have parsed
+ * query and got SqliteStatement as a result. You can modify some parameters of the query
+ * and detokenize it back to SQL string. This is done in 4 steps:
+ * <ul>
+ * <li>Parse SQL query string,</li>
+ * <li>Modify values in parsed statements,</li>
+ * <li>Re-generate tokens in all modified statements,</li>
+ * <li>Detokenize tokens from statements.</li>
+ * </ul>
+ *
+ * This is how it's usually done:
+ * @code
+ * // STEP 1
+ * Parser parser(db->getDialect());
+ * if (!parser.parse("SELECT column FROM test WHERE value = 5") || parser.getQueries().size() == 0)
+ * {
+ * // handle parsing error, or no queries parsed (which is also some kind of error)
+ * return;
+ * }
+ *
+ * SqliteQueryPtr query = parser.getQueries().first();
+ * SqliteSelectPtr select = query.dynamicCast<SqliteSelect>();
+ * if (!select)
+ * {
+ * // we want to deal with the SELECT only
+ * return;
+ * }
+ *
+ * // STEP 2
+ * SqliteSelect::Core* core = select->coreSelects.first();
+ *
+ * // Prepare new result column statement
+ * SqliteSelect::Core::ResultColumn* resCol = new SqliteSelect::Core::ResultColumn();
+ *
+ * SqliteExpr* expr = new SqliteExpr(); // create expression for result column
+ * expr->initLiteral("test value"); // let the expression be a constant literal value
+ *
+ * resCol->attach(resCol->expr, expr); // put the defined expression into result column statement
+ * core->attach(core->resultColumns, resCol); // add new result column to rest of columns
+ *
+ * // STEP 3
+ * select->rebuildTokens();
+ *
+ * // STEP 4
+ * QString newQuery = select->detokenize();
+ * @endcode
+ *
+ * In the result, the newQuery will contain: <tt>SELECT column, 'test value' FROM test WHERE value = 5</tt>.
+ *
+ * @warning It is important to use SqliteStatement::attach() and SqliteStatement::detach()
+ * when modifying AST layout. The tree hierarchy is used to delete objects recurrently,
+ * so deleting the SqliteSelect will also delete all it's children. Assembling or disassembling statements
+ * manually (without SqliteStatement::attach() and SqliteStatement::detach()) is not safe and will most likely
+ * result in a memory leak, or application crash.
+ *
+ * For example of SqliteStatement::detach() usage see section below.
+ *
+ * @section ptr_vs_shared_ptr C++ pointer to SqliteStatement vs. SqliteStatementPtr
+ *
+ * SqliteStatementPtr is a shared pointer (QSharedPointer) to SqliteStatement. All derived classes
+ * also have variations of their types as shared pointers. However only the top level objects
+ * returned from the Parser are actually provided as shared pointers. All children objects are
+ * regular C++ pointers. The reason behind this is to avoid memory leaks. Top level objects from Parser
+ * are shared pointers, so you can use them casually, without worrying who and when should delete them.
+ * On the other hand, any children of those top level objects are regular pointers, cause they will
+ * be deleted automatically when their parent is deleted.
+ *
+ * Sometimes you might want to use just some child statement from parsed query. Normally you would need to
+ * assign that child statement to some local variable and reset its parent to nullptr. Fortunately
+ * SqliteStatement provides handful method SqliteStatement::detach(), which does all that for you.
+ * It also provides detached statement as a new shared pointer, so it's easier to manage it.
+ * Additionally there's a template version of detach() method which can return detached statement
+ * as provided statement type.
+ *
+ * Example:
+ * @code
+ * Parser parser(db->getDialect());
+ * if (!parser.parse("SELECT column FROM test WHERE value = 5") || parser.getQueries().size() == 0)
+ * {
+ * // handle parsing error, or no queries parsed (which is also some kind of error)
+ * return SqliteExprPtr();
+ * }
+ *
+ * SqliteQueryPtr query = parser.getQueries().first();
+ * SqliteSelectPtr select = query.dynamicCast<SqliteSelect>();
+ * if (!select)
+ * {
+ * // we want to deal with the SELECT only
+ * return SqliteExprPtr();
+ * }
+ *
+ * SqliteSelect::Core* core = select->coreSelects.first();
+ *
+ * // Our point is to get the SqliteExpr which represents the result column "column".
+ * SqliteExprPtr expr = core->resultColumns.first().detach<SqliteExpr>();
+ * return expr;
+ * @endcode
+ *
+ * After the above <tt>parser</tt> goes out of scope, so it's deleted and all its parsed
+ * queries get deleted as well, because their shared pointers were not copied anywhere else.
+ * The captured <tt>expr</tt> would normally also be deleted, but when we detached it, it became
+ * an independed entity, with its own lifetime.
+ *
+ * For the opposite operation, use SqliteStatement::attach().
+ */
+class API_EXPORT SqliteStatement : public QObject
+{
+ Q_OBJECT
+
+ public:
+ struct FullObject
+ {
+ enum Type
+ {
+ TABLE,
+ INDEX,
+ TRIGGER,
+ VIEW,
+ DATABASE,
+ NONE
+ };
+
+ bool isValid() const;
+
+ Type type = NONE;
+ TokenPtr database;
+ TokenPtr object;
+ };
+
+ SqliteStatement();
+ SqliteStatement(const SqliteStatement& other);
+ virtual ~SqliteStatement();
+
+ QString detokenize();
+ Range getRange();
+ SqliteStatement* findStatementWithToken(TokenPtr token);
+ SqliteStatement* findStatementWithPosition(quint64 cursorPosition);
+ SqliteStatement* parentStatement();
+ QList<SqliteStatement*> childStatements();
+ QStringList getContextColumns(bool checkParent = true, bool checkChilds = true);
+ QStringList getContextTables(bool checkParent = true, bool checkChilds = true);
+ QStringList getContextDatabases(bool checkParent = true, bool checkChilds = true);
+ TokenList getContextColumnTokens(bool checkParent = true, bool checkChilds = true);
+ TokenList getContextTableTokens(bool checkParent = true, bool checkChilds = true);
+ TokenList getContextDatabaseTokens(bool checkParent = true, bool checkChilds = true);
+ QList<FullObject> getContextFullObjects(bool checkParent = true, bool checkChilds = true);
+ void setSqliteDialect(Dialect dialect);
+ void rebuildTokens();
+ void setParent(QObject* parent);
+ void attach(SqliteStatement*& memberForChild, SqliteStatement* childStatementToAttach);
+ SqliteStatementPtr detach();
+ void processPostParsing();
+ virtual SqliteStatement* clone() = 0;
+
+ template <class T>
+ void attach(QList<T*>& listMemberForChild, T* childStatementToAttach)
+ {
+ listMemberForChild << childStatementToAttach;
+ childStatementToAttach->setParent(this);
+ }
+
+ template <class X>
+ QSharedPointer<X> detach() {return detach().dynamicCast<X>();}
+
+ template <class T>
+ QList<T*> getAllTypedStatements()
+ {
+ QList<T*> results;
+
+ T* casted = dynamic_cast<T*>(this);
+ if (casted)
+ results << casted;
+
+ foreach (SqliteStatement* stmt, getContextStatements(this, false, true))
+ results += stmt->getAllTypedStatements<T>();
+
+ return results;
+ }
+
+ /**
+ * @brief Ordered list of all tokens for this statement.
+ * An ordered list of tokens that represent current statement. Tokens include
+ * Token::SPACE and Token::COMMENT types, so detokenizing this list results
+ * in the equal SQL string as was passed to the parser at the begining.
+ */
+ TokenList tokens;
+
+ /**
+ * @brief Map of grammar terminals and non-terminals into their tokens.
+ * This is map of ordered token lists that represent each node of SQLite grammar definition
+ * used to build this statement. For example grammar definition:
+ * test ::= value1 TERMINAL_TOKEN value2
+ * will result in tokens map containing following entries:
+ * value1 = {list of tokens from value1}
+ * TERMINAL_TOKEN = {list of only one token: TERMINAL_TOKEN}
+ * value2 = {list of tokens from value2}
+ *
+ * In case there are two non-terminals with same name used (for example "name name name"),
+ * then first non-terminal is used as a key just as is, but second is renamed to "name2",
+ * and third to "name3". If we had example:
+ * test ::= value TERMINAL_TOKEN value
+ * then it will result in tokens map containing following entries:
+ * value = {list of tokens from first value}
+ * TERMINAL_TOKEN = {list of only one token: TERMINAL_TOKEN}
+ * value2 = {list of tokens from second value}
+ */
+ QHash<QString,TokenList> tokensMap;
+
+ Dialect dialect = Dialect::Sqlite3;
+
+ protected:
+ QStringList getContextColumns(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ QStringList getContextTables(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ QStringList getContextDatabases(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ TokenList getContextColumnTokens(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ TokenList getContextTableTokens(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ TokenList getContextDatabaseTokens(SqliteStatement* caller, bool checkParent, bool checkChilds);
+ QList<FullObject> getContextFullObjects(SqliteStatement* caller, bool checkParent, bool checkChilds);
+
+ virtual QStringList getColumnsInStatement();
+ virtual QStringList getTablesInStatement();
+ virtual QStringList getDatabasesInStatement();
+ virtual TokenList getColumnTokensInStatement();
+ virtual TokenList getTableTokensInStatement();
+ virtual TokenList getDatabaseTokensInStatement();
+ virtual QList<FullObject> getFullObjectsInStatement();
+ virtual TokenList rebuildTokensFromContents();
+ virtual void evaluatePostParsing();
+
+ static TokenList extractPrintableTokens(const TokenList& tokens, bool skipMeaningless = true);
+ QStringList getStrListFromValue(const QString& value);
+ TokenList getTokenListFromNamedKey(const QString& tokensMapKey, int idx = 0);
+ TokenPtr getDbTokenFromFullname(const QString& tokensMapKey = "fullname");
+ TokenPtr getObjectTokenFromFullname(const QString& tokensMapKey = "fullname");
+ TokenPtr getDbTokenFromNmDbnm(const QString& tokensMapKey1 = "nm", const QString& tokensMapKey2 = "dbnm");
+ TokenPtr getObjectTokenFromNmDbnm(const QString& tokensMapKey1 = "nm", const QString& tokensMapKey2 = "dbnm");
+ TokenList getDbTokenListFromFullname(const QString& tokensMapKey = "fullname");
+ TokenList getObjectTokenListFromFullname(const QString& tokensMapKey = "fullname");
+ TokenList getDbTokenListFromNmDbnm(const QString& tokensMapKey1 = "nm", const QString& tokensMapKey2 = "dbnm");
+ TokenList getObjectTokenListFromNmDbnm(const QString& tokensMapKey1 = "nm", const QString& tokensMapKey2 = "dbnm");
+ FullObject getFullObjectFromFullname(FullObject::Type type, const QString& tokensMapKey = "fullname");
+ FullObject getFullObjectFromNmDbnm(FullObject::Type type, const QString& tokensMapKey1 = "nm", const QString& tokensMapKey2 = "dbnm");
+ FullObject getFirstDbFullObject();
+ FullObject getDbFullObject(TokenPtr dbToken);
+ FullObject getFullObject(SqliteStatement::FullObject::Type type, TokenPtr dbToken, TokenPtr objToken);
+ void setContextDbForFullObject(TokenPtr dbToken);
+
+ /**
+ * @brief Token representing a database.
+ * Keeps db context for getFullObjectsInStatement(), so for example "CREATE TABLE xyz.abc (id)" will know,
+ * that for column "id" the database is "xyz" and table "abc". The value is spread across childrens
+ * of this statement when getContextFullObjects() is called.
+ * The value of this variable is defined in overwritten implementation of getFullObjectsInStatement() method.
+ */
+ TokenPtr dbTokenForFullObjects;
+
+ private:
+ QList<SqliteStatement*> getContextStatements(SqliteStatement* caller, bool checkParent, bool checkChilds);
+};
+
+#endif // SQLITESTATEMENT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitetablerelatedddl.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitetablerelatedddl.h
new file mode 100644
index 0000000..599849a
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitetablerelatedddl.h
@@ -0,0 +1,14 @@
+#ifndef SQLITETABLERELATEDDDL_H
+#define SQLITETABLERELATEDDDL_H
+
+#include "coreSQLiteStudio_global.h"
+
+class API_EXPORT SqliteTableRelatedDdl
+{
+ public:
+ virtual QString getTargetTable() const = 0;
+};
+
+typedef QSharedPointer<SqliteTableRelatedDdl> SqliteTableRelatedDdlPtr;
+
+#endif // SQLITETABLERELATEDDDL_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp
new file mode 100644
index 0000000..88ac28b
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.cpp
@@ -0,0 +1,207 @@
+#include "sqliteupdate.h"
+#include "sqlitequerytype.h"
+#include "sqliteexpr.h"
+#include "parser/statementtokenbuilder.h"
+#include "common/global.h"
+#include "sqlitewith.h"
+#include <QDebug>
+
+SqliteUpdate::SqliteUpdate()
+{
+ queryType = SqliteQueryType::Update;
+}
+
+SqliteUpdate::SqliteUpdate(const SqliteUpdate& other) :
+ SqliteQuery(other), onConflict(other.onConflict), database(other.database), table(other.table), indexedByKw(other.indexedByKw),
+ notIndexedKw(other.notIndexedKw), indexedBy(other.indexedBy)
+{
+ // Special case of deep collection copy
+ SqliteExpr* newExpr = nullptr;
+ foreach (const ColumnAndValue& keyValue, other.keyValueMap)
+ {
+ newExpr = new SqliteExpr(*keyValue.second);
+ newExpr->setParent(this);
+ keyValueMap << ColumnAndValue(keyValue.first, newExpr);
+ }
+
+ DEEP_COPY_FIELD(SqliteExpr, where);
+ DEEP_COPY_FIELD(SqliteWith, with);
+}
+
+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)
+ : SqliteUpdate()
+{
+ this->onConflict = onConflict;
+
+ if (!name2.isNull())
+ {
+ database = name1;
+ table = name2;
+ }
+ else
+ table = name1;
+
+ this->indexedBy = indexedBy;
+ this->indexedByKw = !(indexedBy.isNull());
+ this->notIndexedKw = notIndexedKw;
+ keyValueMap = values;
+
+ this->where = where;
+ if (where)
+ where->setParent(this);
+
+ this->with = with;
+ if (with)
+ with->setParent(this);
+
+ foreach (const ColumnAndValue& keyValue, keyValueMap)
+ keyValue.second->setParent(this);
+}
+
+SqliteStatement*SqliteUpdate::clone()
+{
+ return new SqliteUpdate(*this);
+}
+
+SqliteExpr* SqliteUpdate::getValueForColumnSet(const QString& column)
+{
+ foreach (const ColumnAndValue& keyValue, keyValueMap)
+ {
+ if (keyValue.first == column)
+ return keyValue.second;
+ }
+ return nullptr;
+}
+
+QStringList SqliteUpdate::getColumnsInStatement()
+{
+ QStringList columns;
+ foreach (const ColumnAndValue& keyValue, keyValueMap)
+ columns += keyValue.first;
+
+ return columns;
+}
+
+QStringList SqliteUpdate::getTablesInStatement()
+{
+ return getStrListFromValue(table);
+}
+
+QStringList SqliteUpdate::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteUpdate::getColumnTokensInStatement()
+{
+ // This case is not simple. We only have "setlist" in tokensMap
+ // and it contains entire: col = expr, col = expr.
+ // In order to extract 'col' token, we go through all 'expr',
+ // 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");
+ int setListTokensSize = setListTokens.size();
+ int colNameTokenIdx;
+ SqliteExpr* expr = nullptr;
+ foreach (const ColumnAndValue& keyValue, keyValueMap)
+ {
+ expr = keyValue.second;
+ colNameTokenIdx = setListTokens.indexOf(expr->tokens[0]) - 2;
+ if (colNameTokenIdx < 0 || colNameTokenIdx > setListTokensSize)
+ {
+ qCritical() << "Went out of bounds while looking for column tokens in SqliteUpdate::getColumnTokensInStatement().";
+ continue;
+ }
+ list << setListTokens[colNameTokenIdx];
+ }
+ return list;
+}
+
+TokenList SqliteUpdate::getTableTokensInStatement()
+{
+ if (tokensMap.contains("fullname"))
+ return getObjectTokenListFromFullname();
+
+ return TokenList();
+}
+
+TokenList SqliteUpdate::getDatabaseTokensInStatement()
+{
+ if (tokensMap.contains("fullname"))
+ return getDbTokenListFromFullname();
+
+ if (tokensMap.contains("nm"))
+ return extractPrintableTokens(tokensMap["nm"]);
+
+ return TokenList();
+}
+
+QList<SqliteStatement::FullObject> SqliteUpdate::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+ if (!tokensMap.contains("fullname"))
+ return result;
+
+ // Table object
+ FullObject fullObj = getFullObjectFromFullname(FullObject::TABLE);
+
+ if (fullObj.isValid())
+ result << fullObj;
+
+ // Db object
+ fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ {
+ result << fullObj;
+ dbTokenForFullObjects = fullObj.database;
+ }
+
+ return result;
+}
+
+TokenList SqliteUpdate::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ if (with)
+ builder.withStatement(with);
+
+ builder.withKeyword("UPDATE").withSpace();
+ if (onConflict != SqliteConflictAlgo::null)
+ builder.withKeyword("OR").withSpace().withKeyword(sqliteConflictAlgo(onConflict)).withSpace();
+
+ if (!database.isNull())
+ builder.withOther(database, dialect).withOperator(".");
+
+ builder.withOther(table, dialect).withSpace();
+
+ if (indexedByKw)
+ builder.withKeyword("INDEXED").withSpace().withKeyword("BY").withSpace().withOther(indexedBy, dialect).withSpace();
+ else if (notIndexedKw)
+ builder.withKeyword("NOT").withSpace().withKeyword("INDEXED").withSpace();
+
+ builder.withKeyword("SET").withSpace();
+
+ bool first = true;
+ foreach (const ColumnAndValue& keyVal, keyValueMap)
+ {
+ if (!first)
+ builder.withOperator(",").withSpace();
+
+ builder.withOther(keyVal.first, dialect).withSpace().withOperator("=").withStatement(keyVal.second);
+ first = false;
+ }
+
+ if (where)
+ builder.withSpace().withKeyword("WHERE").withStatement(where);
+
+ builder.withOperator(";");
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h
new file mode 100644
index 0000000..7d6e0c1
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqliteupdate.h
@@ -0,0 +1,51 @@
+#ifndef SQLITEUPDATE_H
+#define SQLITEUPDATE_H
+
+#include "sqlitequery.h"
+#include "sqliteconflictalgo.h"
+
+#include <QStringList>
+#include <QMap>
+
+class SqliteExpr;
+class SqliteWith;
+
+class API_EXPORT SqliteUpdate : public SqliteQuery
+{
+ public:
+ typedef QPair<QString,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,
+ SqliteExpr* where, SqliteWith* with);
+
+ SqliteStatement* clone();
+ SqliteExpr* getValueForColumnSet(const QString& column);
+
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+ QString database = QString::null;
+ QString table = QString::null;
+ bool indexedByKw = false;
+ bool notIndexedKw = false;
+ QString indexedBy = QString::null;
+ QList<ColumnAndValue> keyValueMap;
+ SqliteExpr* where = nullptr;
+ SqliteWith* with = nullptr;
+
+ protected:
+ QStringList getColumnsInStatement();
+ QStringList getTablesInStatement();
+ QStringList getDatabasesInStatement();
+ TokenList getColumnTokensInStatement();
+ TokenList getTableTokensInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteUpdate> SqliteUpdatePtr;
+
+#endif // SQLITEUPDATE_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.cpp
new file mode 100644
index 0000000..ab7d00e
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.cpp
@@ -0,0 +1,56 @@
+#include "sqlitevacuum.h"
+#include "sqlitequerytype.h"
+
+#include <parser/statementtokenbuilder.h>
+
+SqliteVacuum::SqliteVacuum()
+{
+ queryType = SqliteQueryType::Vacuum;
+}
+
+SqliteVacuum::SqliteVacuum(const SqliteVacuum& other) :
+ SqliteQuery(other), database(other.database)
+{
+}
+
+SqliteVacuum::SqliteVacuum(const QString& name)
+ : SqliteVacuum()
+{
+ if (!name.isNull())
+ database = name;
+}
+
+SqliteStatement*SqliteVacuum::clone()
+{
+ return new SqliteVacuum(*this);
+}
+
+QStringList SqliteVacuum::getDatabasesInStatement()
+{
+ return getStrListFromValue(database);
+}
+
+TokenList SqliteVacuum::getDatabaseTokensInStatement()
+{
+ return getTokenListFromNamedKey("nm");
+}
+
+QList<SqliteStatement::FullObject> SqliteVacuum::getFullObjectsInStatement()
+{
+ QList<FullObject> result;
+
+ // Db object
+ FullObject fullObj = getFirstDbFullObject();
+ if (fullObj.isValid())
+ result << fullObj;
+
+ return result;
+}
+
+
+TokenList SqliteVacuum::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withKeyword("VACUUM").withOperator(";");
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.h
new file mode 100644
index 0000000..871b8f4
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitevacuum.h
@@ -0,0 +1,28 @@
+#ifndef SQLITEVACUUM_H
+#define SQLITEVACUUM_H
+
+#include "sqlitequery.h"
+
+#include <QString>
+
+class API_EXPORT SqliteVacuum : public SqliteQuery
+{
+ public:
+ SqliteVacuum();
+ SqliteVacuum(const SqliteVacuum& other);
+ explicit SqliteVacuum(const QString &name);
+
+ SqliteStatement* clone();
+
+ QString database;
+
+ protected:
+ QStringList getDatabasesInStatement();
+ TokenList getDatabaseTokensInStatement();
+ QList<FullObject> getFullObjectsInStatement();
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteVacuum> SqliteVacuumPtr;
+
+#endif // SQLITEVACUUM_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.cpp
new file mode 100644
index 0000000..2b9c99f
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.cpp
@@ -0,0 +1,87 @@
+#include "sqlitewith.h"
+#include "parser/statementtokenbuilder.h"
+#include "sqliteselect.h"
+#include "common/global.h"
+
+SqliteWith::SqliteWith()
+{
+}
+
+SqliteWith::SqliteWith(const SqliteWith& other) :
+ SqliteStatement(other), recursive(other.recursive)
+{
+ DEEP_COPY_COLLECTION(CommonTableExpression, cteList);
+}
+
+SqliteWith* SqliteWith::append(const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select)
+{
+ SqliteWith* with = new SqliteWith();
+ CommonTableExpression* cte = new CommonTableExpression(tableName, indexedColumns, select);
+ cte->setParent(with);
+ with->cteList << cte;
+ return with;
+}
+
+SqliteWith* SqliteWith::append(SqliteWith* with, const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select)
+{
+ if (!with)
+ with = new SqliteWith();
+
+ CommonTableExpression* cte = new CommonTableExpression(tableName, indexedColumns, select);
+ cte->setParent(with);
+ with->cteList << cte;
+ return with;
+}
+
+SqliteStatement*SqliteWith::clone()
+{
+ return new SqliteWith(*this);
+}
+
+TokenList SqliteWith::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+
+ builder.withKeyword("WITH").withSpace();
+ if (recursive)
+ builder.withKeyword("RECURSIVE").withSpace();
+
+ builder.withStatementList(cteList);
+
+ return builder.build();
+}
+
+SqliteWith::CommonTableExpression::CommonTableExpression()
+{
+}
+
+SqliteWith::CommonTableExpression::CommonTableExpression(const SqliteWith::CommonTableExpression& other) :
+ SqliteStatement(other), table(other.table)
+{
+ DEEP_COPY_COLLECTION(SqliteIndexedColumn, indexedColumns);
+ DEEP_COPY_FIELD(SqliteSelect, select);
+}
+
+SqliteWith::CommonTableExpression::CommonTableExpression(const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select) :
+ table(tableName), indexedColumns(indexedColumns), select(select)
+{
+ select->setParent(this);
+}
+
+SqliteStatement*SqliteWith::CommonTableExpression::clone()
+{
+ return new SqliteWith::CommonTableExpression(*this);
+}
+
+TokenList SqliteWith::CommonTableExpression::rebuildTokensFromContents()
+{
+ StatementTokenBuilder builder;
+ builder.withOther(table, dialect);
+
+ if (indexedColumns.size() > 0)
+ builder.withSpace().withParLeft().withStatementList(indexedColumns).withParRight();
+
+ builder.withSpace().withKeyword("AS").withSpace().withParLeft().withStatement(select).withParRight();
+
+ return builder.build();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.h b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.h
new file mode 100644
index 0000000..fe64c9c
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/ast/sqlitewith.h
@@ -0,0 +1,45 @@
+#ifndef SQLITEWITH_H
+#define SQLITEWITH_H
+
+#include "sqlitestatement.h"
+#include "sqliteindexedcolumn.h"
+
+class SqliteSelect;
+
+class SqliteWith : public SqliteStatement
+{
+ public:
+ class CommonTableExpression : public SqliteStatement
+ {
+ public:
+ CommonTableExpression();
+ CommonTableExpression(const CommonTableExpression& other);
+ CommonTableExpression(const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select);
+
+ SqliteStatement* clone();
+
+ QString table;
+ QList<SqliteIndexedColumn*> indexedColumns;
+ SqliteSelect* select = nullptr;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+ };
+
+ SqliteWith();
+ SqliteWith(const SqliteWith& other);
+ static SqliteWith* append(const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select);
+ static SqliteWith* append(SqliteWith* with, const QString& tableName, const QList<SqliteIndexedColumn*>& indexedColumns, SqliteSelect* select);
+
+ SqliteStatement* clone();
+
+ QList<CommonTableExpression*> cteList;
+ bool recursive = false;
+
+ protected:
+ TokenList rebuildTokensFromContents();
+};
+
+typedef QSharedPointer<SqliteWith> SqliteWithPtr;
+
+#endif // SQLITEWITH_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp
new file mode 100644
index 0000000..2088ff2
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.cpp
@@ -0,0 +1,324 @@
+#include "keywords.h"
+#include "sqlite3_parse.h"
+#include "sqlite2_parse.h"
+#include <QDebug>
+#include <QList>
+
+QHash<QString,int> keywords2;
+QHash<QString,int> keywords3;
+QSet<QString> rowIdKeywords;
+QStringList joinKeywords;
+QStringList fkMatchKeywords;
+QStringList conflictAlgoKeywords;
+
+int getKeywordId2(const QString& str)
+{
+ QString upStr = str.toUpper();
+ if (keywords2.contains(upStr))
+ return keywords2[upStr];
+ else
+ return TK2_ID;
+}
+
+int getKeywordId3(const QString& str)
+{
+ QString upStr = str.toUpper();
+ if (keywords3.contains(upStr))
+ return keywords3[upStr];
+ else
+ return TK3_ID;
+}
+
+bool isRowIdKeyword(const QString& str)
+{
+ return rowIdKeywords.contains(str.toUpper());
+}
+
+const QHash<QString,int>& getKeywords2()
+{
+ return keywords2;
+}
+
+const QHash<QString,int>& getKeywords3()
+{
+ return keywords3;
+}
+
+void initKeywords()
+{
+ // SQLite 3
+ keywords3["REINDEX"] = TK3_REINDEX;
+ keywords3["INDEXED"] = TK3_INDEXED;
+ keywords3["INDEX"] = TK3_INDEX;
+ keywords3["DESC"] = TK3_DESC;
+ keywords3["ESCAPE"] = TK3_ESCAPE;
+ keywords3["EACH"] = TK3_EACH;
+ keywords3["CHECK"] = TK3_CHECK;
+ keywords3["KEY"] = TK3_KEY;
+ keywords3["BEFORE"] = TK3_BEFORE;
+ keywords3["FOREIGN"] = TK3_FOREIGN;
+ keywords3["FOR"] = TK3_FOR;
+ keywords3["IGNORE"] = TK3_IGNORE;
+ keywords3["REGEXP"] = TK3_LIKE_KW;
+ keywords3["EXPLAIN"] = TK3_EXPLAIN;
+ keywords3["INSTEAD"] = TK3_INSTEAD;
+ keywords3["ADD"] = TK3_ADD;
+ keywords3["DATABASE"] = TK3_DATABASE;
+ keywords3["AS"] = TK3_AS;
+ keywords3["SELECT"] = TK3_SELECT;
+ keywords3["TABLE"] = TK3_TABLE;
+ keywords3["LEFT"] = TK3_JOIN_KW;
+ keywords3["THEN"] = TK3_THEN;
+ keywords3["END"] = TK3_END;
+ keywords3["DEFERRABLE"] = TK3_DEFERRABLE;
+ keywords3["ELSE"] = TK3_ELSE;
+ keywords3["EXCEPT"] = TK3_EXCEPT;
+ keywords3["TRANSACTION"] = TK3_TRANSACTION;
+ keywords3["ACTION"] = TK3_ACTION;
+ keywords3["ON"] = TK3_ON;
+ keywords3["NATURAL"] = TK3_JOIN_KW;
+ keywords3["ALTER"] = TK3_ALTER;
+ keywords3["RAISE"] = TK3_RAISE;
+ keywords3["EXCLUSIVE"] = TK3_EXCLUSIVE;
+ keywords3["EXISTS"] = TK3_EXISTS;
+ keywords3["SAVEPOINT"] = TK3_SAVEPOINT;
+ keywords3["INTERSECT"] = TK3_INTERSECT;
+ keywords3["TRIGGER"] = TK3_TRIGGER;
+ keywords3["REFERENCES"] = TK3_REFERENCES;
+ keywords3["CONSTRAINT"] = TK3_CONSTRAINT;
+ keywords3["INTO"] = TK3_INTO;
+ keywords3["OFFSET"] = TK3_OFFSET;
+ keywords3["OF"] = TK3_OF;
+ keywords3["SET"] = TK3_SET;
+ keywords3["TEMP"] = TK3_TEMP;
+ keywords3["TEMPORARY"] = TK3_TEMP;
+ keywords3["OR"] = TK3_OR;
+ keywords3["UNIQUE"] = TK3_UNIQUE;
+ keywords3["QUERY"] = TK3_QUERY;
+ keywords3["ATTACH"] = TK3_ATTACH;
+ keywords3["HAVING"] = TK3_HAVING;
+ keywords3["GROUP"] = TK3_GROUP;
+ keywords3["UPDATE"] = TK3_UPDATE;
+ keywords3["BEGIN"] = TK3_BEGIN;
+ keywords3["INNER"] = TK3_JOIN_KW;
+ keywords3["RELEASE"] = TK3_RELEASE;
+ keywords3["BETWEEN"] = TK3_BETWEEN;
+ keywords3["NOTNULL"] = TK3_NOTNULL;
+ keywords3["NOT"] = TK3_NOT;
+ keywords3["NO"] = TK3_NO;
+ keywords3["NULL"] = TK3_NULL;
+ keywords3["LIKE"] = TK3_LIKE_KW;
+ keywords3["CASCADE"] = TK3_CASCADE;
+ keywords3["ASC"] = TK3_ASC;
+ keywords3["DELETE"] = TK3_DELETE;
+ keywords3["CASE"] = TK3_CASE;
+ keywords3["COLLATE"] = TK3_COLLATE;
+ keywords3["CREATE"] = TK3_CREATE;
+ keywords3["CURRENT_DATE"] = TK3_CTIME_KW;
+ keywords3["DETACH"] = TK3_DETACH;
+ keywords3["IMMEDIATE"] = TK3_IMMEDIATE;
+ keywords3["JOIN"] = TK3_JOIN;
+ keywords3["INSERT"] = TK3_INSERT;
+ keywords3["MATCH"] = TK3_MATCH;
+ keywords3["PLAN"] = TK3_PLAN;
+ keywords3["ANALYZE"] = TK3_ANALYZE;
+ keywords3["PRAGMA"] = TK3_PRAGMA;
+ keywords3["ABORT"] = TK3_ABORT;
+ keywords3["VALUES"] = TK3_VALUES;
+ keywords3["VIRTUAL"] = TK3_VIRTUAL;
+ keywords3["LIMIT"] = TK3_LIMIT;
+ keywords3["WHEN"] = TK3_WHEN;
+ keywords3["WHERE"] = TK3_WHERE;
+ keywords3["RENAME"] = TK3_RENAME;
+ keywords3["AFTER"] = TK3_AFTER;
+ keywords3["REPLACE"] = TK3_REPLACE;
+ keywords3["AND"] = TK3_AND;
+ keywords3["DEFAULT"] = TK3_DEFAULT;
+ keywords3["AUTOINCREMENT"] = TK3_AUTOINCR;
+ keywords3["TO"] = TK3_TO;
+ keywords3["IN"] = TK3_IN;
+ keywords3["CAST"] = TK3_CAST;
+ keywords3["COLUMN"] = TK3_COLUMNKW;
+ keywords3["COMMIT"] = TK3_COMMIT;
+ keywords3["CONFLICT"] = TK3_CONFLICT;
+ keywords3["CROSS"] = TK3_JOIN_KW;
+ keywords3["CURRENT_TIMESTAMP"] = TK3_CTIME_KW;
+ keywords3["CURRENT_TIME"] = TK3_CTIME_KW;
+ keywords3["PRIMARY"] = TK3_PRIMARY;
+ keywords3["DEFERRED"] = TK3_DEFERRED;
+ keywords3["DISTINCT"] = TK3_DISTINCT;
+ keywords3["IS"] = TK3_IS;
+ keywords3["DROP"] = TK3_DROP;
+ keywords3["FAIL"] = TK3_FAIL;
+ keywords3["FROM"] = TK3_FROM;
+ keywords3["FULL"] = TK3_JOIN_KW;
+ keywords3["GLOB"] = TK3_LIKE_KW;
+ keywords3["BY"] = TK3_BY;
+ keywords3["IF"] = TK3_IF;
+ keywords3["ISNULL"] = TK3_ISNULL;
+ keywords3["ORDER"] = TK3_ORDER;
+ keywords3["RESTRICT"] = TK3_RESTRICT;
+ keywords3["OUTER"] = TK3_JOIN_KW;
+ keywords3["RIGHT"] = TK3_JOIN_KW;
+ keywords3["ROLLBACK"] = TK3_ROLLBACK;
+ keywords3["ROW"] = TK3_ROW;
+ keywords3["UNION"] = TK3_UNION;
+ keywords3["USING"] = TK3_USING;
+ keywords3["VACUUM"] = TK3_VACUUM;
+ keywords3["VIEW"] = TK3_VIEW;
+ keywords3["INITIALLY"] = TK3_INITIALLY;
+ keywords3["WITHOUT"] = TK3_WITHOUT;
+ keywords3["ALL"] = TK3_ALL;
+ keywords3["WITH"] = TK3_WITH;
+ keywords3["RECURSIVE"] = TK3_RECURSIVE;
+
+ // SQLite 2
+ keywords2["ABORT"] = TK2_ABORT;
+ keywords2["AFTER"] = TK2_AFTER;
+ keywords2["ALL"] = TK2_ALL;
+ keywords2["AND"] = TK2_AND;
+ keywords2["AS"] = TK2_AS;
+ keywords2["ASC"] = TK2_ASC;
+ keywords2["ATTACH"] = TK2_ATTACH;
+ keywords2["BEFORE"] = TK2_BEFORE;
+ keywords2["BEGIN"] = TK2_BEGIN;
+ keywords2["BETWEEN"] = TK2_BETWEEN;
+ keywords2["BY"] = TK2_BY;
+ keywords2["CASCADE"] = TK2_CASCADE;
+ keywords2["CASE"] = TK2_CASE;
+ keywords2["CHECK"] = TK2_CHECK;
+ keywords2["CLUSTER"] = TK2_CLUSTER;
+ keywords2["COLLATE"] = TK2_COLLATE;
+ keywords2["COMMIT"] = TK2_COMMIT;
+ keywords2["CONFLICT"] = TK2_CONFLICT;
+ keywords2["CONSTRAINT"] = TK2_CONSTRAINT;
+ keywords2["COPY"] = TK2_COPY;
+ keywords2["CREATE"] = TK2_CREATE;
+ keywords2["CROSS"] = TK2_JOIN_KW;
+ keywords2["DATABASE"] = TK2_DATABASE;
+ keywords2["DEFAULT"] = TK2_DEFAULT;
+ keywords2["DEFERRED"] = TK2_DEFERRED;
+ keywords2["DEFERRABLE"] = TK2_DEFERRABLE;
+ keywords2["DELETE"] = TK2_DELETE;
+ keywords2["DELIMITERS"] = TK2_DELIMITERS;
+ keywords2["DESC"] = TK2_DESC;
+ keywords2["DETACH"] = TK2_DETACH;
+ keywords2["DISTINCT"] = TK2_DISTINCT;
+ keywords2["DROP"] = TK2_DROP;
+ keywords2["END"] = TK2_END;
+ keywords2["EACH"] = TK2_EACH;
+ keywords2["ELSE"] = TK2_ELSE;
+ keywords2["EXCEPT"] = TK2_EXCEPT;
+ keywords2["EXPLAIN"] = TK2_EXPLAIN;
+ keywords2["FAIL"] = TK2_FAIL;
+ keywords2["FOR"] = TK2_FOR;
+ keywords2["FOREIGN"] = TK2_FOREIGN;
+ keywords2["FROM"] = TK2_FROM;
+ keywords2["FULL"] = TK2_JOIN_KW;
+ keywords2["GLOB"] = TK2_GLOB;
+ keywords2["GROUP"] = TK2_GROUP;
+ keywords2["HAVING"] = TK2_HAVING;
+ keywords2["IGNORE"] = TK2_IGNORE;
+ keywords2["IMMEDIATE"] = TK2_IMMEDIATE;
+ keywords2["IN"] = TK2_IN;
+ keywords2["INDEX"] = TK2_INDEX;
+ keywords2["INITIALLY"] = TK2_INITIALLY;
+ keywords2["INNER"] = TK2_JOIN_KW;
+ keywords2["INSERT"] = TK2_INSERT;
+ keywords2["INSTEAD"] = TK2_INSTEAD;
+ keywords2["INTERSECT"] = TK2_INTERSECT;
+ keywords2["INTO"] = TK2_INTO;
+ keywords2["IS"] = TK2_IS;
+ keywords2["ISNULL"] = TK2_ISNULL;
+ keywords2["JOIN"] = TK2_JOIN;
+ keywords2["KEY"] = TK2_KEY;
+ keywords2["LEFT"] = TK2_JOIN_KW;
+ keywords2["LIKE"] = TK2_LIKE;
+ keywords2["LIMIT"] = TK2_LIMIT;
+ keywords2["MATCH"] = TK2_MATCH;
+ keywords2["NATURAL"] = TK2_JOIN_KW;
+ keywords2["NOT"] = TK2_NOT;
+ keywords2["NOTNULL"] = TK2_NOTNULL;
+ keywords2["NULL"] = TK2_NULL;
+ keywords2["OF"] = TK2_OF;
+ keywords2["OFFSET"] = TK2_OFFSET;
+ keywords2["ON"] = TK2_ON;
+ keywords2["OR"] = TK2_OR;
+ keywords2["ORDER"] = TK2_ORDER;
+ keywords2["OUTER"] = TK2_JOIN_KW;
+ keywords2["PRAGMA"] = TK2_PRAGMA;
+ keywords2["PRIMARY"] = TK2_PRIMARY;
+ keywords2["RAISE"] = TK2_RAISE;
+ keywords2["REFERENCES"] = TK2_REFERENCES;
+ keywords2["REPLACE"] = TK2_REPLACE;
+ keywords2["RESTRICT"] = TK2_RESTRICT;
+ keywords2["RIGHT"] = TK2_JOIN_KW;
+ keywords2["ROLLBACK"] = TK2_ROLLBACK;
+ keywords2["ROW"] = TK2_ROW;
+ keywords2["SELECT"] = TK2_SELECT;
+ keywords2["SET"] = TK2_SET;
+ keywords2["STATEMENT"] = TK2_STATEMENT;
+ keywords2["TABLE"] = TK2_TABLE;
+ keywords2["TEMP"] = TK2_TEMP;
+ keywords2["TEMPORARY"] = TK2_TEMP;
+ keywords2["THEN"] = TK2_THEN;
+ keywords2["TRANSACTION"] = TK2_TRANSACTION;
+ keywords2["TRIGGER"] = TK2_TRIGGER;
+ keywords2["UNION"] = TK2_UNION;
+ keywords2["UNIQUE"] = TK2_UNIQUE;
+ keywords2["UPDATE"] = TK2_UPDATE;
+ keywords2["USING"] = TK2_USING;
+ keywords2["VACUUM"] = TK2_VACUUM;
+ keywords2["VALUES"] = TK2_VALUES;
+ keywords2["VIEW"] = TK2_VIEW;
+ keywords2["WHEN"] = TK2_WHEN;
+ keywords2["WHERE"] = TK2_WHERE;
+
+ rowIdKeywords << "_ROWID_"
+ << "ROWID"
+ << "OID";
+
+
+ joinKeywords << "NATURAL" << "LEFT" << "RIGHT" << "OUTER" << "INNER" << "CROSS";
+ fkMatchKeywords << "SIMPLE" << "FULL" << "PARTIAL";
+ conflictAlgoKeywords << "ROLLBACK" << "ABORT" << "FAIL" << "IGNORE" << "REPLACE";
+}
+
+
+bool isJoinKeyword(const QString &str)
+{
+ return joinKeywords.contains(str, Qt::CaseInsensitive);
+}
+
+QStringList getJoinKeywords()
+{
+ return joinKeywords;
+}
+
+QStringList getFkMatchKeywords()
+{
+ return fkMatchKeywords;
+}
+
+bool isFkMatchKeyword(const QString &str)
+{
+ return fkMatchKeywords.contains(str);
+}
+
+
+bool isKeyword(const QString& str, Dialect dialect)
+{
+ switch (dialect)
+ {
+ case Dialect::Sqlite3:
+ return keywords3.contains(str.toUpper());
+ case Dialect::Sqlite2:
+ return keywords2.contains(str.toUpper());
+ }
+ return false;
+}
+
+QStringList getConflictAlgorithms()
+{
+ return conflictAlgoKeywords;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/keywords.h b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.h
new file mode 100644
index 0000000..a6e1d3d
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/keywords.h
@@ -0,0 +1,123 @@
+#ifndef KEYWORDS_H
+#define KEYWORDS_H
+
+#include "dialect.h"
+#include "coreSQLiteStudio_global.h"
+#include <QString>
+#include <QStringList>
+#include <QHash>
+
+/** @file */
+
+/**
+ * @brief Translates keyword into it's Lemon token ID for SQLite 2 dialect.
+ * @param str The keyword.
+ * @return Lemon generated token ID, or TK2_ID value when the \p str parameter was not recognized as a valid SQLite 2 keyword.
+ *
+ * This method is used internally by the Lexer.
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT int getKeywordId2(const QString& str);
+
+/**
+ * @brief Translates keyword into it's Lemon token ID for SQLite 3 dialect.
+ * @param str The keyword.
+ * @return Lemon generated token ID, or TK3_ID value when the \p str parameter was not recognized as a valid SQLite 3 keyword.
+ *
+ * This method is used internally by the Lexer.
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT int getKeywordId3(const QString& str);
+
+/**
+ * @brief Tests whether given string represents a keyword in given SQLite dialect.
+ * @param str String to test.
+ * @param dialect SQLite dialect.
+ * @return true if the string represents a keyword, or false otherwise.
+ *
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT bool isKeyword(const QString& str, Dialect dialect);
+
+/**
+ * @brief Tests whether given string representing any variation of ROWID.
+ * @param str String to test.
+ * @return true if the value represents ROWID keyword, or false otherwise.
+ *
+ * ROWID keywords understood by SQLite are: <tt>ROWID</tt>, <tt>_ROWID_</tt> and <tt>OID</tt>.
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT bool isRowIdKeyword(const QString& str);
+
+/**
+ * @brief Provides map of SQLite 2 keywords and their Lemon token IDs.
+ * @return Keyword-to-Lemon-ID hash map, keywords are uppercase.
+ */
+API_EXPORT const QHash<QString,int>& getKeywords2();
+
+/**
+ * @brief Provides map of SQLite 3 keywords and their Lemon token IDs.
+ * @return Keyword-to-Lemon-ID hash map, keywords are uppercase.
+ */
+API_EXPORT const QHash<QString,int>& getKeywords3();
+
+/**
+ * @brief Provides list of keywords representing types of SQL joins.
+ * @return Join type keywords.
+ *
+ * Join type keywords are: <tt>NATURAL</tt>, <tt>LEFT</tt>, <tt>RIGHT</tt>, <tt>OUTER</tt>, <tt>INNER</tt>, <tt>CROSS</tt>.
+ *
+ * Join type keywords are distinguished from other keywords, because SQLite grammar definitions
+ * allow those keywords to be used in contexts other than just join type definition.
+ */
+API_EXPORT QStringList getJoinKeywords();
+
+/**
+ * @brief Tests whether the keyword is one of join type keywords.
+ * @param str String to test.
+ * @return true if the value represents join type keyword.
+ *
+ * This method simply tests if given string is on the list returned from getJoinKeywords().
+ *
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT bool isJoinKeyword(const QString& str);
+
+/**
+ * @brief Returns foreign key "match type" keywords.
+ * @return Match type keywords.
+ *
+ * Match type keywords are: <tt>SIMPLE</tt>, <tt>FULL</tt> and <tt>PARTIAL</tt>.
+ *
+ * Foreign key match type keywords are distinguished from other keywords, because SQLite grammar
+ * definitions allow those keywords to be used in contexts other than just foreign key match type definition.
+ */
+API_EXPORT QStringList getFkMatchKeywords();
+
+/**
+ * @brief Tests whether the given value is one of match type keywords.
+ * @param str String to test.
+ * @return true if the value represents match type keywords, false otherwise.
+ *
+ * Comparision is done in case insensitive manner.
+ */
+API_EXPORT bool isFkMatchKeyword(const QString& str);
+
+/**
+ * @brief Initializes internal tables of keywords.
+ *
+ * This has to be (and it is) done at application startup. It defines all internal hash tables
+ * and lists with keywords.
+ */
+API_EXPORT void initKeywords();
+
+/**
+ * @brief Provides list of SQLite conflict algorithm keywords.
+ *
+ * Conflict algorithms keywords are: <tt>ROLLBACK</tt>, <tt>ABORT</tt>, <tt>FAIL</tt>, <tt>IGNORE</tt>, <tt>REPLACE</tt>.
+ *
+ * Those keywords are used for example on GUI, when user has an "On conflict" algorithm to pick from drop-down list.
+ */
+API_EXPORT QStringList getConflictAlgorithms();
+
+#endif // KEYWORDS_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lempar.c b/SQLiteStudio3/coreSQLiteStudio/parser/lempar.c
new file mode 100644
index 0000000..4f9cd5c
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/lempar.c
@@ -0,0 +1,1021 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+**
+** This version of "lempar.c" is modified, slightly, for use by SQLite.
+** The only modifications are the addition of a couple of NEVER()
+** macros to disable tests that are needed in the case of a general
+** LALR(1) grammar but which are always false in the
+** specific grammar used by SQLite.
+*/
+/* First off, code is included that follows the "include" declaration
+** in the input grammar file. */
+#include <stdio.h>
+%%
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+%%
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** ParseTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is ParseTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
+** ParseARG_SDECL A static variable declaration for the %extra_argument
+** ParseARG_PDECL A parameter declaration for the %extra_argument
+** ParseARG_STORE Code to store %extra_argument into yypParser
+** ParseARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+%%
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+#define GET_CONTEXT yyParser* yypParser = pParser; ParseARG_FETCH
+
+/* The yyzerominor constant is used to initialize instances of
+** YYMINORTYPE objects to zero. */
+static const YYMINORTYPE yyzerominor = { 0 };
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage. For production
+** code the yytestcase() macro should be turned off. But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+%%
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+%%
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ YYACTIONTYPE stateno; /* The state-number */
+ YYCODETYPE major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+ QList<Token*>* tokens = nullptr;
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+ int yyidxMax; /* Maximum value of yyidx */
+#endif
+ int yyerrcnt; /* Shifts left before out of the error */
+ ParseARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+void *ParseCopyParserState(void* other)
+{
+ yyParser *pParser;
+ yyParser *otherParser = (yyParser*)other;
+
+ // Copy parser
+ pParser = (yyParser*)malloc((size_t)sizeof(yyParser));
+ memcpy(pParser, other, (size_t)sizeof(yyParser));
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = malloc((size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)other)->yystack, (size_t)stackSize);
+#endif
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(otherParser->yystack[i].tokens);
+ }
+
+ return pParser;
+}
+
+void ParseAddToken(void* other, Token* token)
+{
+ yyParser *otherParser = (yyParser*)other;
+ if (otherParser->yyidx < 0)
+ return; // Nothing on stack yet. Might happen when parsing just whitespaces, nothing else.
+
+ otherParser->yystack[otherParser->yyidx].tokens->append(token);
+}
+
+void ParseRestoreParserState(void* saved, void* target)
+{
+ yyParser *pParser = (yyParser*)target;
+ yyParser *savedParser = (yyParser*)saved;
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+ memcpy(pParser, saved, (size_t)sizeof(yyParser));
+
+ for (int i = 0; i <= savedParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(savedParser->yystack[i].tokens);
+ }
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = relloc(pParser->yystack, (size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)saved)->yystack, (size_t)stackSize);
+#endif
+}
+
+void ParseFreeSavedState(void* other)
+{
+ yyParser *pParser = (yyParser*)other;
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ free(other);
+}
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *const yyTokenName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.
+*/
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
+#endif
+ }
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to Parse and ParseFree.
+*/
+void *ParseAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+#ifdef YYTRACKMAXSTACKDEPTH
+ pParser->yyidxMax = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ pParser->yystack = NULL;
+ pParser->yystksz = 0;
+ yyGrowStack(pParser);
+#endif
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(
+ yyParser *yypParser, /* The parser */
+ YYCODETYPE yymajor, /* Type code for object to destroy */
+ YYMINORTYPE *yypminor /* The object to be destroyed */
+){
+ ParseARG_FETCH;
+ if (parserContext->executeRules)
+ {
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+%%
+ default: break; /* If no destructor action specified: do nothing */
+ }
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+ /* There is no mechanism by which the parser stack can be popped below
+ ** empty in SQLite. */
+ if( pParser->yyidx<0 ) return 0;
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor(pParser, yymajor, &yytos->minor);
+ delete yytos->tokens;
+ yytos->tokens = nullptr;
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from ParseAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void ParseFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ /* In SQLite, we never try to destroy a parser that was not successfully
+ ** created in the first place. */
+ if( pParser==0 ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int ParseStackPeak(void *p){
+ yyParser *pParser = (yyParser*)p;
+ return pParser->yyidxMax;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+ GET_CONTEXT;
+
+ if( stateno>YY_SHIFT_COUNT
+ || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
+#ifdef YYFALLBACK
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0
+ && parserContext->doFallbacks ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
+#if YY_SHIFT_MIN+YYWILDCARD<0
+ j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+ j<YY_ACTTAB_COUNT &&
+#endif
+ yy_lookahead[j]==YYWILDCARD
+ ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
+ }
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ int stateno, /* Current state number */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+#ifdef YYERRORSYMBOL
+ if( stateno>YY_REDUCE_COUNT ){
+ return yy_default[stateno];
+ }
+#else
+ assert( stateno<=YY_REDUCE_COUNT );
+#endif
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+#ifdef YYERRORSYMBOL
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }
+#else
+ assert( i>=0 && i<YY_ACTTAB_COUNT );
+ assert( yy_lookahead[i]==iLookAhead );
+#endif
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ ParseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( yypParser->yyidx>yypParser->yyidxMax ){
+ yypParser->yyidxMax = yypParser->yyidx;
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = (YYACTIONTYPE)yyNewState;
+ yytos->major = (YYCODETYPE)yyMajor;
+ yytos->minor = *yypMinor;
+ yytos->tokens = new QList<Token*>();
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+%%
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ ParseARG_FETCH;
+ SqliteStatement* objectForTokens = 0;
+ QStringList noTokenInheritanceFields;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && yyruleno>=0
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ }
+#endif /* NDEBUG */
+
+ /* Silence complaints from purify about yygotominor being uninitialized
+ ** in some cases when it is copied into the stack after the following
+ ** switch. yygotominor is uninitialized when a rule reduces that does
+ ** not set the value of its left-hand side nonterminal. Leaving the
+ ** value of the nonterminal uninitialized is utterly harmless as long
+ ** as the value is never used. So really the only thing this code
+ ** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
+ */
+ /*memset(&yygotominor, 0, sizeof(yygotominor));*/
+ yygotominor = yyzerominor;
+
+
+ if (parserContext->executeRules)
+ {
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+%%
+ };
+ }
+ assert( yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0])) );
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+
+ // Store tokens for the rule in parser context
+ QList<Token*> allTokens;
+ QList<Token*> allTokensWithAllInherited;
+ QString keyForTokensMap;
+ int tokensMapKeyCnt;
+ if (parserContext->setupTokens)
+ {
+ if (objectForTokens)
+ {
+ // In case this is a list with recurrent references we need
+ // to clear tokens before adding the new and extended list.
+ objectForTokens->tokens.clear();
+ }
+
+ QList<Token*> tokens;
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ tokens.clear();
+ const char* fieldName = yyTokenName[yypParser->yystack[i].major];
+ if (parserContext->isManagedToken(yypParser->yystack[i].minor.yy0))
+ tokens += yypParser->yystack[i].minor.yy0;
+
+ tokens += *(yypParser->yystack[i].tokens);
+
+ if (!noTokenInheritanceFields.contains(fieldName))
+ {
+ if (objectForTokens)
+ {
+ keyForTokensMap = fieldName;
+ tokensMapKeyCnt = 2;
+ while (objectForTokens->tokensMap.contains(keyForTokensMap))
+ keyForTokensMap = fieldName + QString::number(tokensMapKeyCnt++);
+
+ objectForTokens->tokensMap[keyForTokensMap] = parserContext->getTokenPtrList(tokens);
+ }
+
+ allTokens += tokens;
+ }
+ else
+ {
+ // If field is mentioned only once, then only one occurance of it will be ignored.
+ // Second one should be inherited. See "anylist" definition for explanation why.
+ noTokenInheritanceFields.removeOne(fieldName);
+ }
+ allTokensWithAllInherited += tokens;
+ }
+ if (objectForTokens)
+ {
+ objectForTokens->tokens += parserContext->getTokenPtrList(allTokens);
+ }
+ }
+
+ // Clear token lists
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ delete yypParser->yystack[i].tokens;
+ yypParser->yystack[i].tokens = nullptr;
+ }
+
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+ if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+ /* If we are not debugging and the reduce action popped at least
+ ** one element off the stack, then we can push the new element back
+ ** onto the stack here, and skip the stack overflow test in yy_shift().
+ ** That gives a significant speed improvement. */
+ if( yysize ){
+ yypParser->yyidx++;
+ yymsp -= yysize-1;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yymsp->minor = yygotominor;
+ if (parserContext->setupTokens)
+ *(yypParser->yystack[yypParser->yyidx].tokens) = allTokens;
+ }else
+#endif
+ {
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ if (parserContext->setupTokens)
+ {
+ QList<Token*>* tokensPtr = yypParser->yystack[yypParser->yyidx].tokens;
+ *tokensPtr = allTokensWithAllInherited + *tokensPtr;
+ }
+ }
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ ParseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ ParseARG_FETCH;
+#define TOKEN (yyminor.yy0)
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ ParseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ParseAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void Parse(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ ParseTOKENTYPE yyminor /* The value for the token */
+ ParseARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ int yyendofinput; /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
+ yyminorunion = yyzerominor;
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ yypParser->yystack[0].tokens = new QList<Token*>();
+ }
+ yyminorunion.yy0 = yyminor;
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ yyendofinput = (yymajor==0);
+#endif
+ ParseARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s [%s] (lemon type: %s)\n",
+ yyTracePrompt,
+ yyminor->value.toLatin1().data(),
+ yyminor->typeString().toLatin1().data(),
+ yyTokenName[yymajor]); }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ yymajor = YYNOCODE;
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
+ int yymx;
+#endif
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_reduce_action(
+ yypParser->yystack[yypParser->yyidx].stateno,
+ YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+ /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+ ** do any kind of error recovery. Instead, simply invoke the syntax
+ ** error routine and continue going as if nothing had happened.
+ **
+ ** Applications can set this macro (for example inside %include) if
+ ** they intend to abandon the parse upon the first syntax error seen.
+ */
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp
new file mode 100644
index 0000000..c85b3ba
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.cpp
@@ -0,0 +1,314 @@
+#include "lexer.h"
+#include "keywords.h"
+#include "lexer_low_lev.h"
+#include "sqlite2_parse.h"
+#include "sqlite3_parse.h"
+#include <QString>
+#include <QMultiHash>
+#include <QDebug>
+
+QHash<Token::Type,QSet<TokenPtr> > Lexer::everyTokenType2;
+QHash<Token::Type,QSet<TokenPtr> > Lexer::everyTokenType3;
+QHash<Token*,TokenPtr> Lexer::everyTokenTypePtrMap;
+TokenPtr Lexer::semicolonTokenSqlite2;
+TokenPtr Lexer::semicolonTokenSqlite3;
+
+Lexer::Lexer(Dialect dialect)
+ : dialect(dialect), sqlToTokenize(QString::null)
+{
+}
+
+Lexer::~Lexer()
+{
+ cleanUp();
+}
+
+TokenList Lexer::tokenize(const QString &sql)
+{
+ TokenList resultList;
+ int lgt;
+ TokenPtr token;
+ QString str = sql;
+
+ quint64 pos = 0;
+ for (;str.size() > 0;)
+ {
+ if (tolerant)
+ token = TolerantTokenPtr::create();
+ else
+ token = TokenPtr::create();
+
+ lgt = lexerGetToken(str, token, dialect == Dialect::Sqlite2 ? 2 : 3, tolerant);
+ if (lgt == 0)
+ break;
+
+ token->value = str.mid(0, lgt);
+ token->start = pos;
+ token->end = pos + lgt - 1;
+
+ resultList << token;
+ str = str.mid(lgt);
+ pos += lgt;
+ }
+
+ return resultList;
+}
+
+void Lexer::prepare(const QString &sql)
+{
+ sqlToTokenize = sql;
+ tokenPosition = 0;
+}
+
+TokenPtr Lexer::getToken()
+{
+ if (sqlToTokenize.isEmpty())
+ return TokenPtr();
+
+ TokenPtr token;
+ if (tolerant)
+ token = TolerantTokenPtr::create();
+ else
+ token = TokenPtr::create();
+
+ int lgt = lexerGetToken(sqlToTokenize, token, dialect == Dialect::Sqlite2 ? 2 : 3, tolerant);
+ if (lgt == 0)
+ return TokenPtr();
+
+ token->value = sqlToTokenize.mid(0, lgt);
+ token->start = tokenPosition;
+ token->end = tokenPosition + lgt - 1;
+
+ sqlToTokenize = sqlToTokenize.mid(lgt);
+ tokenPosition += lgt;
+
+ return token;
+}
+
+void Lexer::cleanUp()
+{
+ sqlToTokenize.clear();
+ tokenPosition = 0;
+}
+
+void Lexer::setTolerantMode(bool enabled)
+{
+ tolerant = enabled;
+}
+
+QSet<TokenPtr> Lexer::getEveryTokenType()
+{
+ return getEveryTokenType({Token::BIND_PARAM, Token::BLOB, Token::COMMENT, Token::FLOAT,
+ Token::INTEGER, Token::KEYWORD, Token::OPERATOR, Token::OTHER,
+ Token::PAR_LEFT, Token::PAR_RIGHT, Token::SPACE, Token::STRING,
+ Token::INVALID});
+}
+
+QSet<TokenPtr> Lexer::getEveryTokenType(QSet<Token::Type> types)
+{
+ // Process set of types
+ QSet<TokenPtr> results;
+ QHashIterator<Token::Type,QSet<TokenPtr> > i(
+ dialect == Dialect::Sqlite2 ? everyTokenType2 : everyTokenType3
+ );
+ while (i.hasNext())
+ {
+ i.next();
+ if (types.contains(i.key()))
+ {
+ QSet<TokenPtr> tk = i.value();
+ results.unite(tk);
+ }
+ }
+ return results;
+}
+
+bool Lexer::isEnd() const
+{
+ return sqlToTokenize.isEmpty();
+}
+
+TokenPtr Lexer::getSemicolonToken(Dialect dialect)
+{
+ return (dialect == Dialect::Sqlite3) ? semicolonTokenSqlite3 : semicolonTokenSqlite2;
+}
+
+void Lexer::staticInit()
+{
+ createTokenType(Dialect::Sqlite3, TK3_SPACE, Token::SPACE, " ");
+ createTokenType(Dialect::Sqlite3, TK3_COMMENT, Token::COMMENT, "--");
+ createTokenType(Dialect::Sqlite3, TK3_MINUS, Token::OPERATOR, "-");
+ createTokenType(Dialect::Sqlite3, TK3_SPACE, Token::SPACE, " ");
+ createTokenType(Dialect::Sqlite3, TK3_LP, Token::PAR_LEFT, "(");
+ createTokenType(Dialect::Sqlite3, TK3_RP, Token::PAR_RIGHT, ")");
+ semicolonTokenSqlite3 =
+ createTokenType(Dialect::Sqlite3, TK3_SEMI, Token::OPERATOR, ";");
+ createTokenType(Dialect::Sqlite3, TK3_PLUS, Token::OPERATOR, "+");
+ createTokenType(Dialect::Sqlite3, TK3_STAR, Token::OPERATOR, "*");
+ createTokenType(Dialect::Sqlite3, TK3_SLASH, Token::OPERATOR, "/");
+ createTokenType(Dialect::Sqlite3, TK3_COMMENT, Token::COMMENT, "/* */");
+ createTokenType(Dialect::Sqlite3, TK3_EQ, Token::OPERATOR, "=");
+ createTokenType(Dialect::Sqlite3, TK3_EQ, Token::OPERATOR, "==");
+ createTokenType(Dialect::Sqlite3, TK3_LE, Token::OPERATOR, "<=");
+ createTokenType(Dialect::Sqlite3, TK3_NE, Token::OPERATOR, "<>");
+ createTokenType(Dialect::Sqlite3, TK3_NE, Token::OPERATOR, "!=");
+ createTokenType(Dialect::Sqlite3, TK3_LSHIFT, Token::OPERATOR, "<<");
+ createTokenType(Dialect::Sqlite3, TK3_LT, Token::OPERATOR, "<");
+ createTokenType(Dialect::Sqlite3, TK3_GE, Token::OPERATOR, ">=");
+ createTokenType(Dialect::Sqlite3, TK3_RSHIFT, Token::OPERATOR, ">>");
+ createTokenType(Dialect::Sqlite3, TK3_GT, Token::OPERATOR, ">");
+ createTokenType(Dialect::Sqlite3, TK3_BITOR, Token::OPERATOR, "|");
+ createTokenType(Dialect::Sqlite3, TK3_CONCAT, Token::OPERATOR, "||");
+ createTokenType(Dialect::Sqlite3, TK3_COMMA, Token::OPERATOR, ",");
+ createTokenType(Dialect::Sqlite3, TK3_BITAND, Token::OPERATOR, "&");
+ createTokenType(Dialect::Sqlite3, TK3_BITNOT, Token::OPERATOR, "~");
+ createTokenType(Dialect::Sqlite3, TK3_STRING, Token::STRING, "' '");
+ createTokenType(Dialect::Sqlite3, TK3_ID, Token::OTHER, "id");
+ createTokenType(Dialect::Sqlite3, TK3_DOT, Token::OPERATOR, ".");
+ createTokenType(Dialect::Sqlite3, TK3_INTEGER, Token::INTEGER, "1");
+ createTokenType(Dialect::Sqlite3, TK3_FLOAT, Token::FLOAT, "1.0");
+ createTokenType(Dialect::Sqlite3, TK3_VARIABLE, Token::BIND_PARAM, "?");
+ createTokenType(Dialect::Sqlite3, TK3_BLOB, Token::BLOB, "X'53'");
+
+ // Contextual ID tokens
+ createTokenType(Dialect::Sqlite3, TK3_ID_DB, Token::CTX_DATABASE, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_TAB, Token::CTX_TABLE, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_TAB_NEW, Token::CTX_TABLE_NEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_COL, Token::CTX_COLUMN, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_COL_NEW, Token::CTX_COLUMN_NEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_COL_TYPE, Token::CTX_COLUMN_TYPE, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_COLLATE, Token::CTX_COLLATION, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_FN, Token::CTX_FUNCTION, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_ERR_MSG, Token::CTX_ERROR_MESSAGE, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_IDX, Token::CTX_INDEX, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_IDX_NEW, Token::CTX_INDEX_NEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_VIEW, Token::CTX_VIEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_VIEW_NEW, Token::CTX_VIEW_NEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_JOIN_OPTS, Token::CTX_JOIN_OPTS, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_CONSTR, Token::CTX_CONSTRAINT, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_FK_MATCH, Token::CTX_FK_MATCH, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_TRANS, Token::CTX_TRANSACTION, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_ALIAS, Token::CTX_ALIAS, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_PRAGMA, Token::CTX_PRAGMA, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_TRIG, Token::CTX_TRIGGER, "");
+ createTokenType(Dialect::Sqlite3, TK3_ID_TRIG_NEW, Token::CTX_TRIGGER_NEW, "");
+ createTokenType(Dialect::Sqlite3, TK3_CTX_ROWID_KW, Token::CTX_ROWID_KW, "ROWID");
+ createTokenType(Dialect::Sqlite3, TK3_ID, Token::CTX_OLD_KW, "OLD");
+ createTokenType(Dialect::Sqlite3, TK3_ID, Token::CTX_NEW_KW, "NEW");
+
+ QHashIterator<QString,int> i3(getKeywords3());
+ while (i3.hasNext())
+ {
+ i3.next();
+ createTokenType(Dialect::Sqlite3, i3.value(), Token::KEYWORD, i3.key());
+ }
+
+ //
+ // SQLite 2
+ //
+
+ createTokenType(Dialect::Sqlite2, TK2_SPACE, Token::SPACE, " ");
+ createTokenType(Dialect::Sqlite2, TK2_COMMENT, Token::COMMENT, "--");
+ createTokenType(Dialect::Sqlite2, TK2_MINUS, Token::OPERATOR, "-");
+ createTokenType(Dialect::Sqlite2, TK2_SPACE, Token::SPACE, " ");
+ createTokenType(Dialect::Sqlite2, TK2_LP, Token::PAR_LEFT, "(");
+ createTokenType(Dialect::Sqlite2, TK2_RP, Token::PAR_RIGHT, ")");
+ semicolonTokenSqlite2 =
+ createTokenType(Dialect::Sqlite2, TK2_SEMI, Token::OPERATOR, ";");
+ createTokenType(Dialect::Sqlite2, TK2_PLUS, Token::OPERATOR, "+");
+ createTokenType(Dialect::Sqlite2, TK2_STAR, Token::OPERATOR, "*");
+ createTokenType(Dialect::Sqlite2, TK2_SLASH, Token::OPERATOR, "/");
+ createTokenType(Dialect::Sqlite2, TK2_COMMENT, Token::COMMENT, "/* */");
+ createTokenType(Dialect::Sqlite2, TK2_EQ, Token::OPERATOR, "=");
+ createTokenType(Dialect::Sqlite2, TK2_EQ, Token::OPERATOR, "==");
+ createTokenType(Dialect::Sqlite2, TK2_LE, Token::OPERATOR, "<=");
+ createTokenType(Dialect::Sqlite2, TK2_NE, Token::OPERATOR, "<>");
+ createTokenType(Dialect::Sqlite2, TK2_NE, Token::OPERATOR, "!=");
+ createTokenType(Dialect::Sqlite2, TK2_LSHIFT, Token::OPERATOR, "<<");
+ createTokenType(Dialect::Sqlite2, TK2_LT, Token::OPERATOR, "<");
+ createTokenType(Dialect::Sqlite2, TK2_GE, Token::OPERATOR, ">=");
+ createTokenType(Dialect::Sqlite2, TK2_RSHIFT, Token::OPERATOR, ">>");
+ createTokenType(Dialect::Sqlite2, TK2_GT, Token::OPERATOR, ">");
+ createTokenType(Dialect::Sqlite2, TK2_BITOR, Token::OPERATOR, "|");
+ createTokenType(Dialect::Sqlite2, TK2_CONCAT, Token::OPERATOR, "||");
+ createTokenType(Dialect::Sqlite2, TK2_COMMA, Token::OPERATOR, ",");
+ createTokenType(Dialect::Sqlite2, TK2_BITAND, Token::OPERATOR, "&");
+ createTokenType(Dialect::Sqlite2, TK2_BITNOT, Token::OPERATOR, "~");
+ createTokenType(Dialect::Sqlite2, TK2_STRING, Token::STRING, "' '");
+ createTokenType(Dialect::Sqlite2, TK2_ID, Token::OTHER, "id");
+ createTokenType(Dialect::Sqlite2, TK2_DOT, Token::OPERATOR, ".");
+ createTokenType(Dialect::Sqlite2, TK2_INTEGER, Token::INTEGER, "1");
+ createTokenType(Dialect::Sqlite2, TK2_FLOAT, Token::FLOAT, "1.0");
+ createTokenType(Dialect::Sqlite2, TK2_VARIABLE, Token::BIND_PARAM, "?");
+
+ // Contextual ID tokens
+ createTokenType(Dialect::Sqlite2, TK2_ID_DB, Token::CTX_DATABASE, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_TAB, Token::CTX_TABLE, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_TAB_NEW, Token::CTX_TABLE_NEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_COL, Token::CTX_COLUMN, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_COL_NEW, Token::CTX_COLUMN_NEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_COL_TYPE, Token::CTX_COLUMN_TYPE, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_FN, Token::CTX_FUNCTION, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_ERR_MSG, Token::CTX_ERROR_MESSAGE, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_IDX, Token::CTX_INDEX, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_IDX_NEW, Token::CTX_INDEX_NEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_VIEW, Token::CTX_VIEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_VIEW_NEW, Token::CTX_VIEW_NEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_JOIN_OPTS, Token::CTX_JOIN_OPTS, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_CONSTR, Token::CTX_CONSTRAINT, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_FK_MATCH, Token::CTX_FK_MATCH, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_TRANS, Token::CTX_TRANSACTION, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_ALIAS, Token::CTX_ALIAS, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_PRAGMA, Token::CTX_PRAGMA, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_TRIG, Token::CTX_TRIGGER, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID_TRIG_NEW, Token::CTX_TRIGGER_NEW, "");
+ createTokenType(Dialect::Sqlite2, TK2_ID, Token::CTX_ROWID_KW, "ROWID");
+ createTokenType(Dialect::Sqlite2, TK2_ID, Token::CTX_OLD_KW, "OLD");
+ createTokenType(Dialect::Sqlite2, TK2_ID, Token::CTX_NEW_KW, "NEW");
+
+ QHashIterator<QString,int> i2(getKeywords2());
+ while (i2.hasNext())
+ {
+ i2.next();
+ createTokenType(Dialect::Sqlite2, i2.value(), Token::KEYWORD, i2.key());
+ }
+}
+
+QString Lexer::detokenize(const TokenList& tokens)
+{
+ if (tokens.size() == 0)
+ return "";
+
+ QString str;
+ foreach (TokenPtr token, tokens)
+ str += token->value;
+
+ return str;
+}
+
+TokenList Lexer::tokenize(const QString& sql, Dialect dialect)
+{
+ Lexer lexer(dialect);
+ return lexer.tokenize(sql);
+}
+
+TokenPtr Lexer::getEveryTokenTypePtr(Token *token)
+{
+ if (everyTokenTypePtrMap.contains(token))
+ return everyTokenTypePtrMap[token];
+
+ qDebug() << "Queried token not in Lexer::everyTokenTypePtrMap:" << token->toString();
+ return TokenPtr();
+}
+
+TokenPtr Lexer::createTokenType(Dialect dialect, int lemonType, Token::Type type, const QString &value)
+{
+ TokenPtr tokenPtr = TokenPtr::create(lemonType, type, value, -100, -100);
+ if (dialect == Dialect::Sqlite2)
+ everyTokenType2[type] << tokenPtr;
+ else
+ everyTokenType3[type] << tokenPtr;
+
+ everyTokenTypePtrMap[tokenPtr.data()] = tokenPtr;
+ return tokenPtr;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer.h b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.h
new file mode 100644
index 0000000..b21639e
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer.h
@@ -0,0 +1,254 @@
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "token.h"
+#include "dialect.h"
+
+#include <QList>
+#include <QString>
+#include <QSet>
+
+/**
+ * @brief Lexer for SQLite gramma.
+ *
+ * Lexer (aka tokenizer) splits SQL string into tokens.
+ * Tokens can be then used to syntax analysis, or for other purposes.
+ *
+ * It is useful if you have to modify some entities in the query,
+ * such as string, or object name, but you don't want to deal with
+ * all escape characters in the name, or other special characters.
+ * Lexer packs such entiries into separate tokens and gives them
+ * type, so you know what is the token representing.
+ */
+class API_EXPORT Lexer
+{
+ public:
+ /**
+ * @brief Creates lexer for given dialect.
+ * @param dialect SQLite dialect.
+ */
+ Lexer(Dialect dialect);
+
+ /**
+ * @brief Releases resources.
+ */
+ virtual ~Lexer();
+
+ /**
+ * @brief Tokenizes (splits into tokens) given SQL query.
+ * @param sql SQL query to tokenize.
+ * @return List of tokens produced from tokenizing query.
+ */
+ TokenList tokenize(const QString& sql);
+
+ /**
+ * @brief Stores given SQL query internally for further processing by the lexer.
+ * @param sql Query to remember.
+ *
+ * This method should be followed by calls to getToken().
+ */
+ void prepare(const QString& sql);
+
+ /**
+ * @brief Gets next token from query defined with prepare().
+ * @return Token read from the query, or null token if no more tokens are available.
+ *
+ * Each call to this method generates token for next part of the query, not tokenized yet.
+ * Usual flow for this method looks like this:
+ * @code
+ * QString query = "...";
+ * TokenPtr token;
+ * lexer.prepare(query);
+ * while (token = lexer.getToken())
+ * {
+ * // do stuff with the token
+ * }
+ * @endcode
+ */
+ TokenPtr getToken();
+
+ /**
+ * @brief Clears query stored with prepare().
+ */
+ void cleanUp();
+
+ /**
+ * @brief Enables or disabled tolerant mode.
+ * @param enabled If true, then all multi-line and unfinished tokens (strings, comments) will be reported
+ * with invalid=true in TolerantToken, but the token itself will have type like it was finished.
+ */
+ void setTolerantMode(bool enabled);
+
+ /**
+ * @brief Provides static sample tokens of all possible types.
+ * @return All possible token types.
+ * This method uses static set of tokens, so there's no need
+ * to delete them outside.
+ *
+ * It's used by Parser to try every token type as a possible candidate for a next valid token.
+ * You should not need to use this method.
+ */
+ QSet<TokenPtr> getEveryTokenType();
+
+ /**
+ * @brief Gets static sample tokens of given types.
+ * @param types List of token types to get tokens for. Last element in the list must be Token::INVALID.
+ *
+ * It's used by Parser to try every token type as a possible candidate for a next valid token.
+ * You should not need to use this method.
+ *
+ * @overload
+ */
+ QSet<TokenPtr> getEveryTokenType(QSet<Token::Type> types);
+
+ /**
+ * @brief Tests whether lexer finished reading all tokens from the query.
+ * @return true if there is no more tokens to be read, or false otherwise.
+ *
+ * This method simply checks whether there's any characters in the query to be tokenized.
+ * The query is the one defined with prepare(). Query shrinks with very call to getToken()
+ * and once there's no more characters to consume by getToken(), this method will return false.
+ *
+ * If you call getToken() after isEnd() returned false, the getToken() will return Token::INVALID token.
+ */
+ bool isEnd() const;
+
+ /**
+ * @brief Initializes internal set of static tokens.
+ * Initializes internal set of tokens used by getEveryTokenType().
+ */
+ static void staticInit();
+
+ /**
+ * @brief Restores string from token list.
+ * @param tokens List of tokens.
+ * @return String that was represented by tokens.
+ *
+ * It simply joins values of all tokens from the list using empty string separator (that is no separator at all).
+ */
+ static QString detokenize(const TokenList& tokens);
+
+ /**
+ * @brief Tokenizes given SQL query with given dialect.
+ * @param sql SQL query to tokenize.
+ * @param dialect SQLite dialect to use when tokenizing.
+ * @return List of tokens from tokenizing.
+ *
+ * This method is a shortcut for:
+ * @code
+ * Lexer lexer(dialect);
+ * lexer.tokenize(sql);
+ * @endcode
+ */
+ static TokenList tokenize(const QString& sql, Dialect dialect);
+
+ /**
+ * @brief Translates token pointer into common token shared pointer.
+ * @param token Token pointer to translate.
+ * @return Shared pointer if found, or null pointer if not found.
+ *
+ * This method should be used against token pointers extracted from getEveryTokenType() results.
+ * Then pointer from any TokenPtr (returned from getEveryTokenType()) is extracted using the
+ * QSharedPointer::data(), then this method can be used to return back to the QSharedPointer.
+ *
+ * As Lexer keeps static internal list of tokens representing token types,
+ * it can translate token pointer into shared pointer by comparing them.
+ *
+ * This method and getEveryTokenType() methods are used strictly by Parser and you should not
+ * need to use them.
+ */
+ static TokenPtr getEveryTokenTypePtr(Token* token);
+
+ /**
+ * @brief Provides token representing semicolon in given SQLite dialect.
+ * @param dialect Dialect to use.
+ * @return Token representing semicolon.
+ *
+ * This is used by Parser to complete the parsed query in case the input query did not end with semicolon.
+ * Given the \p dialect it provides proper token for that dialect (they are different by Lemon token ID).
+ */
+ static TokenPtr getSemicolonToken(Dialect dialect);
+
+ private:
+ /**
+ * @brief Creates token for every token type internal tables.
+ * @param dialect SQLite dialect to create token for.
+ * @param lemonType Lemon token ID for this token type.
+ * @param type SQLiteStudio token type.
+ * @param value Sample value for the token.
+ * @return Created token.
+ *
+ * Every token type internal tables are populated using this method.
+ *
+ * @see getEveryTokenType()
+ */
+ static TokenPtr createTokenType(Dialect dialect, int lemonType, Token::Type type, const QString& value);
+
+ /**
+ * @brief Current "tolerant mode" flag.
+ *
+ * @see setTolerantMode()
+ */
+ bool tolerant = false;
+
+ /**
+ * @brief Lexer's SQLite dialect.
+ */
+ Dialect dialect;
+
+ /**
+ * @brief SQL query to be tokenized with getToken().
+ *
+ * It's defined with prepare().
+ */
+ QString sqlToTokenize;
+
+ /**
+ * @brief Current tokenizer position in the sqlToTokenize.
+ *
+ * This position index is used to track which SQL characters should be tokenized
+ * on next call to getToken().
+ *
+ * It's reset to 0 by prepare() and cleanUp().
+ */
+ quint64 tokenPosition;
+
+ /**
+ * @brief Internal table of every token type for SQLite 2.
+ *
+ * @see semicolonTokenSqlite3
+ */
+ static TokenPtr semicolonTokenSqlite2;
+
+ /**
+ * @brief Internal table of every token type for SQLite 3.
+ *
+ * Internal token type table contains single token per token type, so it can be used to probe the Parser
+ * for next valid token candidates.
+ */
+ static TokenPtr semicolonTokenSqlite3;
+
+ /**
+ * @brief Internal table of every token type for SQLite 2.
+ *
+ * @see everyTokenType3
+ */
+ static QHash<Token::Type,QSet<TokenPtr> > everyTokenType2;
+
+ /**
+ * @brief Internal table of every token type for SQLite 3.
+ *
+ * Set of tokens representing all token types, including diversification by values for keywords and operators.
+ * It's used by the Parser to probe candidates for next valid token.
+ */
+ static QHash<Token::Type,QSet<TokenPtr> > everyTokenType3;
+
+ /**
+ * @brief Map of every token type pointer to its QSharedPointer from internal tables.
+ *
+ * This is used by getEveryTokenTypePtr().
+ */
+ static QHash<Token*,TokenPtr> everyTokenTypePtrMap;
+};
+
+#endif // LEXER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp
new file mode 100644
index 0000000..894afd1
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.cpp
@@ -0,0 +1,470 @@
+#include "lexer_low_lev.h"
+#include "token.h"
+#include "keywords.h"
+#include "sqlite3_parse.h"
+#include "sqlite2_parse.h"
+#include "common/utils.h"
+#include "common/utils_sql.h"
+
+#include <QByteArray>
+#include <QChar>
+#include <QDebug>
+
+//
+// Low-level lexer routines based on tokenizer from SQLite 3.7.15.2
+//
+
+bool isIdChar(const QChar& c)
+{
+ return c.isPrint() && !c.isSpace() && !doesObjectNeedWrapping(c);
+}
+
+int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tolerant)
+{
+ if (sqliteVersion < 2 || sqliteVersion > 3)
+ {
+ qCritical() << "lexerGetToken() called with invalid sqliteVersion:" << sqliteVersion;
+ return 0;
+ }
+
+ if (tolerant && !token.dynamicCast<TolerantToken>())
+ {
+ qCritical() << "lexerGetToken() called with tolerant=true, but not a TolerantToken entity!";
+ return 0;
+ }
+
+ bool v3 = sqliteVersion == 3;
+ int i;
+ QChar c;
+ QChar z0 = charAt(z, 0);
+
+ for (;;)
+ {
+ if (z0.isSpace())
+ {
+ for(i=1; charAt(z, i).isSpace(); i++) {}
+ token->lemonType = v3 ? TK3_SPACE : TK2_SPACE;
+ token->type = Token::SPACE;
+ return i;
+ }
+ if (z0 == '-')
+ {
+ if (charAt(z, 1) == '-')
+ {
+ for (i=2; (c = charAt(z, i)) != 0 && c != '\n'; i++) {}
+ token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT;
+ token->type = Token::COMMENT;
+ return i;
+ }
+ token->lemonType = v3 ? TK3_MINUS : TK2_MINUS;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '(')
+ {
+ token->lemonType = v3 ? TK3_LP : TK2_LP;
+ token->type = Token::PAR_LEFT;
+ return 1;
+ }
+ if (z0 == ')')
+ {
+ token->lemonType = v3 ? TK3_RP : TK2_RP;
+ token->type = Token::PAR_RIGHT;
+ return 1;
+ }
+ if (z0 == ';')
+ {
+ token->lemonType = v3 ? TK3_SEMI : TK2_SEMI;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '+')
+ {
+ token->lemonType = v3 ? TK3_PLUS : TK2_PLUS;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '*')
+ {
+ token->lemonType = v3 ? TK3_STAR : TK2_STAR;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '/')
+ {
+ if ( charAt(z, 1) != '*' )
+ {
+ token->lemonType = v3 ? TK3_SLASH : TK2_SLASH;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+
+ if ( charAt(z, 2) == 0 )
+ {
+ token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT;
+ token->type = Token::COMMENT;
+ if (tolerant)
+ token.dynamicCast<TolerantToken>()->invalid = true;
+
+ return 2;
+ }
+ for (i = 3, c = charAt(z, 2); (c != '*' || charAt(z, i) != '/') && (c = charAt(z, i)) != 0; i++) {}
+
+ if (tolerant && (c != '*' || charAt(z, i) != '/'))
+ token.dynamicCast<TolerantToken>()->invalid = true;
+
+ if ( c > 0 )
+ i++;
+ token->lemonType = v3 ? TK3_COMMENT : TK2_COMMENT;
+ token->type = Token::COMMENT;
+ return i;
+ }
+ if (z0 == '%')
+ {
+ token->lemonType = v3 ? TK3_REM : TK2_REM;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '=')
+ {
+ token->lemonType = v3 ? TK3_EQ : TK2_EQ;
+ token->type = Token::OPERATOR;
+ return 1 + (charAt(z, 1) == '=');
+ }
+ if (z0 == '<')
+ {
+ if ( (c = charAt(z, 1)) == '=' )
+ {
+ token->lemonType = v3 ? TK3_LE : TK2_LE;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ else if ( c == '>' )
+ {
+ token->lemonType = v3 ? TK3_NE : TK2_NE;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ else if( c == '<' )
+ {
+ token->lemonType = v3 ? TK3_LSHIFT : TK2_LSHIFT;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_LT : TK2_LT;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ }
+ if (z0 == '>')
+ {
+ if ( (c = charAt(z, 1)) == '=' )
+ {
+ token->lemonType = v3 ? TK3_GE : TK2_GE;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ else if ( c == '>' )
+ {
+ token->lemonType = v3 ? TK3_RSHIFT : TK2_RSHIFT;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_GT : TK2_GT;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ }
+ if (z0 == '!')
+ {
+ if ( charAt(z, 1) != '=' )
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ return 2;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_NE : TK2_NE;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ }
+ if (z0 == '|')
+ {
+ if( charAt(z, 1) != '|' )
+ {
+ token->lemonType = v3 ? TK3_BITOR : TK2_BITOR;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_CONCAT : TK2_CONCAT;
+ token->type = Token::OPERATOR;
+ return 2;
+ }
+ }
+ if (z0 == ',')
+ {
+ token->lemonType = v3 ? TK3_COMMA : TK2_COMMA;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '&')
+ {
+ token->lemonType = v3? TK3_BITAND : TK2_BITAND;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '~')
+ {
+ token->lemonType = v3? TK3_BITNOT : TK2_BITAND;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ if (z0 == '`' ||
+ z0 == '\'' ||
+ z0 == '"')
+ {
+ QChar delim = z0;
+ for (i = 1; (c = charAt(z, i)) != 0; i++)
+ {
+ if ( c == delim )
+ {
+ if( charAt(z, i+1) == delim )
+ i++;
+ else
+ break;
+ }
+ }
+ if ( c == '\'' )
+ {
+ token->lemonType = v3? TK3_STRING : TK2_STRING;
+ token->type = Token::STRING;
+ return i+1;
+ }
+ else if ( c != 0 )
+ {
+ token->lemonType = v3 ? TK3_ID : TK2_ID;
+ token->type = Token::OTHER;
+ return i+1;
+ }
+ else if (tolerant)
+ {
+ if (z0 == '\'')
+ {
+ token->lemonType = v3 ? TK3_STRING : TK2_STRING;
+ token->type = Token::STRING;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_ID : TK2_ID;
+ token->type = Token::OTHER;
+ }
+ token.dynamicCast<TolerantToken>()->invalid = true;
+ return i;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ return i;
+ }
+ }
+ if (z0 == '.')
+ {
+ if( !charAt(z, 1).isDigit() )
+ {
+ token->lemonType = v3 ? TK3_DOT : TK2_DOT;
+ token->type = Token::OPERATOR;
+ return 1;
+ }
+ /*
+ * If the next character is a digit, this is a floating point
+ * number that begins with ".". Fall thru into the next case
+ */
+ }
+ if (z0.isDigit())
+ {
+ token->lemonType = v3 ? TK3_INTEGER : TK2_INTEGER;
+ token->type = Token::INTEGER;
+ if (v3 && charAt(z, 0) == '0' && (charAt(z, 1) == 'x' || charAt(z, 1) == 'X') && isHex(charAt(z, 2)))
+ {
+ for (i=3; isHex(charAt(z, i)); i++) {}
+ return i;
+ }
+ for (i=0; charAt(z, i).isDigit(); i++) {}
+ if ( charAt(z, i) == '.' )
+ {
+ i++;
+ while ( charAt(z, i).isDigit() )
+ i++;
+
+ token->lemonType = v3 ? TK3_FLOAT : TK2_FLOAT;
+ token->type = Token::FLOAT;
+ }
+ if ( (charAt(z, i) == 'e' || charAt(z, i) == 'E') &&
+ ( charAt(z, i+1).isDigit()
+ || ((charAt(z, i+1) == '+' || charAt(z, i+1) == '-') && charAt(z, i+2).isDigit())
+ )
+ )
+ {
+ i += 2;
+ while ( charAt(z, i+2).isDigit() )
+ i++;
+
+ token->lemonType = v3 ? TK3_FLOAT : TK2_FLOAT;
+ token->type = Token::FLOAT;
+ }
+ while ( isIdChar(charAt(z, i)) )
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ i++;
+ }
+ return i;
+ }
+ if (z0 == '[')
+ {
+ for (i = 1, c = z0; c!=']' && (c = charAt(z, i)) != 0; i++) {}
+ if (c == ']')
+ {
+ token->lemonType = v3 ? TK3_ID : TK2_ID;
+ token->type = Token::OTHER;
+ }
+ else if (tolerant)
+ {
+ token->lemonType = v3 ? TK3_ID : TK2_ID;
+ token->type = Token::OTHER;
+ token.dynamicCast<TolerantToken>()->invalid = true;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ }
+ return i;
+ }
+ if (z0 == '?')
+ {
+ token->lemonType = v3 ? TK3_VARIABLE : TK2_VARIABLE;
+ token->type = Token::BIND_PARAM;
+ for (i=1; charAt(z, i+2).isDigit(); i++) {}
+ return i;
+ }
+ if (z0 == '$' ||
+ z0 == '@' || /* For compatibility with MS SQL Server */
+ z0 == ':')
+ {
+ int n = 0;
+ token->lemonType = v3 ? TK3_VARIABLE : TK2_VARIABLE;
+ token->type = Token::BIND_PARAM;
+ for (i = 1; (c = charAt(z, i)) != 0; i++)
+ {
+ if ( isIdChar(c) )
+ {
+ n++;
+ }
+ else if ( c == '(' && n > 0 )
+ {
+ do
+ {
+ i++;
+ }
+ while ( (c = charAt(z, i)) != 0 && !c.isSpace() && c != ')' );
+
+ if ( c==')' )
+ {
+ i++;
+ }
+ else
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ }
+ break;
+ }
+ else if ( c == ':' && charAt(z, i+1) == ':' )
+ {
+ i++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if( n == 0 )
+ {
+ token->lemonType = v3 ? TK3_ILLEGAL : TK2_ILLEGAL;
+ token->type = Token::INVALID;
+ }
+
+ return i;
+ }
+ if ((z0 == 'x' ||
+ z0 == 'X') &&
+ v3)
+ {
+ if ( charAt(z, 1) == '\'' )
+ {
+ token->lemonType = TK3_BLOB;
+ token->type = Token::BLOB;
+ for (i = 2; isXDigit(charAt(z, i)); i++) {}
+ if (charAt(z, i) != '\'' || i%2)
+ {
+ if (tolerant)
+ {
+ token->lemonType = TK3_BLOB;
+ token->type = Token::BLOB;
+ token.dynamicCast<TolerantToken>()->invalid = true;
+ }
+ else
+ {
+ token->lemonType = TK3_ILLEGAL;
+ token->type = Token::INVALID;
+ }
+ while (charAt(z, i) > 0 && charAt(z, i) != '\'')
+ i++;
+ }
+ if ( charAt(z, i) > 0 )
+ i++;
+
+ return i;
+ }
+ /* Otherwise fall through to the next case */
+ }
+ //default:
+ {
+ if (!isIdChar(z0))
+ break;
+
+ for (i = 1; isIdChar(charAt(z, i)); i++) {}
+
+ if (v3)
+ token->lemonType = getKeywordId3(z.mid(0, i));
+ else
+ token->lemonType = getKeywordId2(z.mid(0, i));
+
+ if (token->lemonType == TK3_ID || token->lemonType == TK2_ID)
+ token->type = Token::OTHER;
+ else
+ token->type = Token::KEYWORD;
+
+ return i;
+ }
+ }
+
+ if (v3)
+ token->lemonType = TK3_ILLEGAL;
+ else
+ token->lemonType = TK2_ILLEGAL;
+
+ token->type = Token::INVALID;
+ return 1;
+}
+
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h
new file mode 100644
index 0000000..87ba7e5
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/lexer_low_lev.h
@@ -0,0 +1,27 @@
+#ifndef LEXER_LOW_LEV_H
+#define LEXER_LOW_LEV_H
+
+#include "parser/token.h"
+#include <QString>
+
+/** @file */
+
+/**
+ * @brief Low level tokenizer function used by the Lexer.
+ * @param z Query to tokenize.
+ * @param[out] token Token container to fill with values. Can be also a TolerantToken.
+ * @param sqliteVersion SQLite version, for which the tokenizer should work (2 or 3).
+ * Version affects the list of recognized keywords, a BLOB expression and an object name wrapper with the grave accent character (`).
+ * @param tolerant If true, then all multi-line and unfinished tokens (strings, comments)
+ * will be reported with invalid=true in TolerantToken, but the token itself will have type like it was finished.
+ * If this is true, then \p token must be of type TolerantToken, otherwise the the method will return 0 and log a critical error.
+ * @return Lemon token ID (see sqlite2_parse.h and sqlite3_parse.h for possible token IDs).
+ *
+ * You shouldn't normally need to use this method. Instead of that, use Lexer class, as it provides higher level API.
+ *
+ * Most of the method code was taken from SQLite tokenizer code. It is modified to support both SQLite 2 and 3 grammas
+ * and other SQLiteStudio specific features.
+ */
+int lexerGetToken(const QString& z, TokenPtr token, int sqliteVersion, bool tolerant = false);
+
+#endif // LEXER_LOW_LEV_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
new file mode 100644
index 0000000..23a4b55
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
@@ -0,0 +1,323 @@
+#include "parser.h"
+#include "parsercontext.h"
+#include "parsererror.h"
+#include "lexer.h"
+#include "../db/db.h"
+#include "ast/sqliteselect.h"
+#include <QStringList>
+#include <QDebug>
+
+// Generated in sqlite*_parse.c by lemon,
+// but not exported in any header
+void* sqlite3_parseAlloc(void *(*mallocProc)(size_t));
+void sqlite3_parseFree(void *p, void (*freeProc)(void*));
+void sqlite3_parse(void *yyp, int yymajor, Token* yyminor, ParserContext* parserContext);
+void sqlite3_parseTrace(FILE *stream, char *zPrefix);
+void* sqlite3_parseCopyParserState(void* other);
+void sqlite3_parseRestoreParserState(void* saved, void* target);
+void sqlite3_parseFreeSavedState(void* other);
+void sqlite3_parseAddToken(void* other, Token* token);
+
+void* sqlite2_parseAlloc(void *(*mallocProc)(size_t));
+void sqlite2_parseFree(void *p, void (*freeProc)(void*));
+void sqlite2_parse(void *yyp, int yymajor, Token* yyminor, ParserContext* parserContext);
+void sqlite2_parseTrace(FILE *stream, char *zPrefix);
+void* sqlite2_parseCopyParserState(void* other);
+void sqlite2_parseRestoreParserState(void* saved, void* target);
+void sqlite2_parseFreeSavedState(void* other);
+void sqlite2_parseAddToken(void* other, Token* token);
+
+Parser::Parser(Dialect dialect)
+{
+ this->dialect = dialect;
+ init();
+}
+
+Parser::~Parser()
+{
+ cleanUp();
+}
+
+void Parser::cleanUp()
+{
+ if (lexer)
+ {
+ delete lexer;
+ lexer = nullptr;
+ }
+
+ if (context)
+ {
+ delete context;
+ context = nullptr;
+ }
+}
+
+void Parser::fillSqliteDialect()
+{
+ foreach (SqliteQueryPtr query, context->parsedQueries)
+ query->setSqliteDialect(dialect);
+}
+
+void *Parser::parseAlloc(void *(*mallocProc)(size_t))
+{
+ if (dialect == Dialect::Sqlite2)
+ return sqlite2_parseAlloc(mallocProc);
+ else
+ return sqlite3_parseAlloc(mallocProc);
+}
+
+void Parser::parseFree(void *p, void (*freeProc)(void *))
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseFree(p, freeProc);
+ else
+ sqlite3_parseFree(p, freeProc);
+}
+
+void Parser::parse(void *yyp, int yymajor, TokenPtr yyminor, ParserContext *parserContext)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parse(yyp, yymajor, yyminor.data(), parserContext);
+ else
+ sqlite3_parse(yyp, yymajor, yyminor.data(), parserContext);
+}
+
+void Parser::parseTrace(FILE *stream, char *zPrefix)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseTrace(stream, zPrefix);
+ else
+ sqlite3_parseTrace(stream, zPrefix);
+}
+
+void *Parser::parseCopyParserState(void *other)
+{
+ if (dialect == Dialect::Sqlite2)
+ return sqlite2_parseCopyParserState(other);
+ else
+ return sqlite3_parseCopyParserState(other);
+}
+
+void Parser::parseRestoreParserState(void *saved, void *target)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseRestoreParserState(saved, target);
+ else
+ sqlite3_parseRestoreParserState(saved, target);
+}
+
+void Parser::parseFreeSavedState(void *other)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseFreeSavedState(other);
+ else
+ sqlite3_parseFreeSavedState(other);
+}
+
+void Parser::parseAddToken(void *other, TokenPtr token)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseAddToken(other, token.data());
+ else
+ sqlite3_parseAddToken(other, token.data());
+}
+
+bool Parser::parse(const QString &sql, bool ignoreMinorErrors)
+{
+ context->ignoreMinorErrors = ignoreMinorErrors;
+ return parseInternal(sql, false);
+}
+
+bool Parser::parseInternal(const QString &sql, bool lookForExpectedToken)
+{
+ void* pParser = parseAlloc( malloc );
+ if (debugLemon)
+ {
+ char* label = nullptr;
+ if (dialect == Dialect::Sqlite2)
+ label = const_cast<char*>("[LEMON2]: ");
+ else
+ label = const_cast<char*>("[LEMON3]: ");
+
+ parseTrace(stderr, label);
+ }
+
+ reset();
+ lexer->prepare(sql);
+ context->setupTokens = !lookForExpectedToken;
+ context->executeRules = !lookForExpectedToken;
+ context->doFallbacks = !lookForExpectedToken;
+ context->dialect = dialect;
+
+ TokenPtr token = lexer->getToken();
+ if (!token.isNull())
+ context->addManagedToken(token);
+
+ bool endsWithSemicolon = false;
+
+ while (token)
+ {
+ if (token->type == Token::SPACE ||
+ token->type == Token::COMMENT ||
+ token->type == Token::INVALID)
+ {
+ parseAddToken(pParser, token);
+ token = lexer->getToken();
+ if (token)
+ context->addManagedToken(token);
+
+ continue;
+ }
+
+ endsWithSemicolon = (token->type == Token::OPERATOR && token->value == ";");
+
+ parse(pParser, token->lemonType, token, context);
+ token = lexer->getToken();
+ if (!token.isNull())
+ context->addManagedToken(token);
+ }
+
+ if (lookForExpectedToken)
+ {
+ expectedTokenLookup(pParser);
+ }
+ else
+ {
+ if (!endsWithSemicolon)
+ {
+ token = Lexer::getSemicolonToken(dialect);
+ parse(pParser, token->lemonType, token, context);
+ }
+
+ qint64 endIdx = sql.length();
+ TokenPtr endToken = TokenPtr::create(0, Token::INVALID, QString::null, endIdx, endIdx);
+ parse(pParser, 0, endToken, context);
+ }
+
+ fillSqliteDialect();
+
+ // Free all non-termials having destructors
+ parseFree(pParser, free);
+
+ context->flushErrors();
+
+ if (context->isSuccessful())
+ {
+ for (SqliteQueryPtr query : context->parsedQueries)
+ query->processPostParsing();
+ }
+
+ return context->isSuccessful();
+}
+
+TokenList Parser::getNextTokenCandidates(const QString &sql)
+{
+ context->ignoreMinorErrors = true;
+ parseInternal(sql, true);
+ TokenList results = acceptedTokens;
+ acceptedTokens.clear();
+ return results;
+}
+
+bool Parser::isSuccessful() const
+{
+ return context->isSuccessful();
+}
+
+void Parser::reset()
+{
+ acceptedTokens.clear();
+ lexer->cleanUp();
+ context->cleanUp();
+}
+
+SqliteExpr *Parser::parseExpr(const QString &sql)
+{
+ SqliteSelectPtr select = parse<SqliteSelect>("SELECT "+sql+";");
+ if (!select || select->coreSelects.size() == 0 || select->coreSelects.first()->resultColumns.size() == 0)
+ return nullptr;
+
+ SqliteExpr* expr = select->coreSelects.first()->resultColumns.first()->expr;
+ expr->setParent(nullptr);
+ return expr;
+}
+
+void Parser::expectedTokenLookup(void* pParser)
+{
+ void* savedParser = parseCopyParserState(pParser);
+
+ ParserContext tempContext;
+ tempContext.executeRules = false;
+ tempContext.executeRules = false;
+ tempContext.doFallbacks = false;
+ QSet<TokenPtr> tokenSet =
+ lexer->getEveryTokenType({
+ Token::KEYWORD, Token::OTHER, Token::PAR_LEFT, Token::PAR_RIGHT, Token::OPERATOR,
+ Token::CTX_COLLATION, Token::CTX_COLUMN, Token::CTX_DATABASE, Token::CTX_FUNCTION,
+ Token::CTX_INDEX, Token::CTX_JOIN_OPTS, Token::CTX_TABLE, Token::CTX_TRIGGER,
+ Token::CTX_VIEW, Token::CTX_FK_MATCH, Token::CTX_ERROR_MESSAGE, Token::CTX_PRAGMA,
+ Token::CTX_ALIAS, Token::CTX_TABLE_NEW, Token::CTX_INDEX_NEW, Token::CTX_TRIGGER_NEW,
+ Token::CTX_VIEW_NEW, Token::CTX_COLUMN_NEW, Token::CTX_TRANSACTION,
+ Token::CTX_CONSTRAINT, Token::CTX_COLUMN_TYPE, Token::CTX_OLD_KW, Token::CTX_NEW_KW,
+ Token::CTX_ROWID_KW, Token::INVALID
+ });
+
+ foreach (TokenPtr token, tokenSet)
+ {
+ parse(pParser, token->lemonType, token, &tempContext);
+
+ if (tempContext.isSuccessful())
+ acceptedTokens += token;
+
+ tempContext.cleanUp();
+ parseRestoreParserState(savedParser, pParser);
+ }
+ parseFreeSavedState(savedParser);
+}
+
+void Parser::init()
+{
+ lexer = new Lexer(dialect);
+ context = new ParserContext();
+}
+
+const QList<ParserError *> &Parser::getErrors()
+{
+ return context->getErrors();
+}
+
+QString Parser::getErrorString()
+{
+ QStringList msgs;
+ foreach (ParserError* error, getErrors())
+ {
+ msgs += error->getMessage();
+ }
+ return msgs.join(",\n");
+}
+
+TokenList Parser::getParsedTokens()
+{
+ return context->getManagedTokens();
+}
+
+void Parser::setLemonDebug(bool enabled)
+{
+ debugLemon = enabled;
+}
+
+void Parser::setDialect(Dialect dialect)
+{
+ if (this->dialect == dialect)
+ return;
+
+ this->dialect = dialect;
+ delete lexer;
+ lexer = new Lexer(dialect);
+}
+
+const QList<SqliteQueryPtr>& Parser::getQueries()
+{
+ return context->getQueries();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h
new file mode 100644
index 0000000..aaf3962
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.h
@@ -0,0 +1,360 @@
+#ifndef PARSER_H
+#define PARSER_H
+
+#include "token.h"
+#include "../dialect.h"
+#include "ast/sqlitequery.h"
+#include "ast/sqliteexpr.h"
+
+class Lexer;
+class ParserContext;
+class ParserError;
+
+/**
+ * @brief SQL parser.
+ *
+ * The Parser analyzes given query and produces an Abstract Syntax Tree (AST).
+ * The AST is a tree of objects describing parsed query.
+ *
+ * Typical use case would be:
+ * @code
+ * Parser parser(db->getDialect());
+ * if (parser.parse(queryString))
+ * {
+ * QList<SqliteQueryPtr> queries = parser.getQueries();
+ * qDebug() << "number of queries parsed:" << queries.size();
+ * foreach (SqliteQueryPtr query, queries)
+ * {
+ * // do stuff with parsed queries
+ * // ...
+ * if (query.dynamicCast<SqliteSelect>())
+ * {
+ * qDebug() << "it's a select!";
+ * }
+ * }
+ * }
+ * else
+ * {
+ * qDebug() << "Error while parsing:" << parser.getErrorString();
+ * }
+ * @endcode
+ *
+ * There's also a convenient parse<T>() method with template argument.
+ *
+ * There is a getNextTokenCandidates() to ask for all valid (according to syntax
+ * rules) token types to be used after given query string,
+ *
+ * Finally, there is a parseExpr() to parse just a SQLite expression
+ * (http://sqlite.org/lang_expr.html).
+ *
+ * Parser works basing on SQLite grammar defined in sqlite2.y and sqlite3.y files.
+ * Since there are 2 completly separate grammar definitions, there are 2 dialects
+ * that the parser works with.
+ *
+ * This is a high-level API to the Lemon Parser, the original SQLite parser.
+ */
+class API_EXPORT Parser
+{
+ public:
+ /**
+ * @brief Creates parser for given SQLite dialect.
+ * @param dialect SQLite dialect to use. Can be changed later with setDialect().
+ */
+ Parser(Dialect dialect);
+
+ /**
+ * @brief Releases internal resources.
+ */
+ virtual ~Parser();
+
+ /**
+ * @brief Enables or disables low-level debug messages for this parser.
+ * @param enabled true to enable, false to disable debug messages.
+ *
+ * Enabling this causes detailed debug messages from the Lemon parser
+ * to be printed. It is useful if you cannot understand why the parser
+ * thinks that the query is incorrect, etc.
+ */
+ void setLemonDebug(bool enabled);
+
+ /**
+ * @brief Changes dialect used by parser.
+ * @param dialect Dialect to use.
+ */
+ void setDialect(Dialect dialect);
+
+ /**
+ * @brief Parses given query string.
+ * @param sql SQL query string to parse. Can be multiple queries separated with semicolon.
+ * @param ignoreMinorErrors If true, then parser will ignore minor errors. Detailed descritpion below.
+ * @return true if the query was successfully parsed, or false if not.
+ *
+ * When the parser encounters syntax error, it stops and returns false. The AST objects (parsed queries)
+ * are partially filled with data - as much as it was possible till the error. Errors can be examined
+ * with getErrors() or getErrorString().
+ *
+ * The \p ignoreMinorErrors allows to ignore minor syntax errors. The minor error is the error
+ * when for example there's a SELECT query, but no result column was typed yet. Normally this is incorrect
+ * query, cause SELECT statement requires at least 1 result column, but we can tell parser to ignore it.
+ *
+ * The usual case for minor error is when there's a SQLite expression missing at position, where it's expected,
+ * or when the expression is incomplete, like <tt>database.table.</tt> (no column name as the last part).
+ */
+ bool parse(const QString& sql, bool ignoreMinorErrors = false);
+
+ /**
+ * @brief Parses SQLite expression.
+ * @param sql SQLite expression.
+ * @return Parsed object, or null on failure. Parser doesn't own parsed object, you have to take care of deleting it.
+ *
+ * SQLite expression is any expression that you could type after <tt>"SELECT * FROM WHERE"</tt>, etc.
+ * It's syntax is described at: http://sqlite.org/lang_expr.html
+ */
+ SqliteExpr* parseExpr(const QString& sql);
+
+ /**
+ * @brief Parses given query and returns it AST specialized object.
+ * @tparam T Type of AST object to parse into.
+ * @param query SQL query string to parse.
+ * @return Shared pointer to the parsed AST object, or null pointer if the query could not be parsed,
+ * or the parsed object was not of the requested type.
+ *
+ * This is a convenient method to parse string query, pick first parsed query from getQueries()
+ * and case it into desired AST object type. If this process fails at any point, the result returned will be
+ * a null pointer.
+ *
+ * Example:
+ * @code
+ * Parser parser(db->getDialect());
+ * SqliteSelectPtr select = parser.parse<SelectPtr>(queryString);
+ * if (!select)
+ * {
+ * qCritical() << "Could not parse" << queryString << "to a SELECT statement, details:" << parser.getErrorString();
+ * return;
+ * }
+ * // do stuff with the 'select' object
+ * // ...
+ * @endcode
+ */
+ template <class T>
+ QSharedPointer<T> parse(const QString& query)
+ {
+ if (!parse(query) || getQueries().size() == 0)
+ return QSharedPointer<T>();
+
+ return getQueries().first().dynamicCast<T>();
+ }
+
+ /**
+ * @brief Tests what are possible valid candidates for the next token.
+ * @param sql Part of the SQL query to check for the next token.
+ * @return List of token candidates.
+ *
+ * This method gets list of all token types from Lexer::getEveryTokenType() and tests which of them does the parser
+ * accept for the next token after the given query.
+ *
+ * You should treat the results of this method as a list of token <b>types</b>, rather than explicit tokens.
+ * Each token in the results represents a logical grammar entity. You should look at the Token::type and Token::value,
+ * while the Token::value is meaningful only for Token::KEYWORD, or Token::OPERATOR. For other token types, the value
+ * is just an example value (like for Token::INTEGER all numbers are valid candidates, not just one returned
+ * from this method).
+ */
+ TokenList getNextTokenCandidates(const QString& sql);
+
+ /**
+ * @brief Provides list of queries parsed recently by the parser.
+ * @return List of queries.
+ *
+ * On successful execution this list should contain at least 1 query, unless parsed query
+ * was a blank string - in that case this method will return list with no elements.
+ *
+ * In case of parsing error it's undefined how many elements will be in the list
+ * and also how much of the information will be filled in the queries - it depends on where the error appeared.
+ */
+ const QList<SqliteQueryPtr>& getQueries();
+
+ /**
+ * @brief Provides list of errors that occurred during parsing.
+ * @return List of errors.
+ *
+ * Usually there's just one error, but there are cases when there might be more error on the list.
+ * That would be for example if you type "!" somewhere in the query where it should not be.
+ * Parser can deal with such errors and proceed. Such errors are later reported as failed parsing after all,
+ * but parser can continue and provide more data for AST objects (even they will be result of failed parsing process)
+ * and find other errors. In such cases, there can be 2, or even more errors on the list.
+ */
+ const QList<ParserError*>& getErrors();
+
+ /**
+ * @brief Provides error message from recent failed parsing process.
+ * @return Error message.
+ *
+ * This is convenient method to get first error getom getErrors() and return message from it.
+ */
+ QString getErrorString();
+
+ /**
+ * @brief Provides list of tokens procudes during parsing process.
+ * @return List of tokens.
+ *
+ * Parser tokenizes query in order to parse it. It stores those tokens, so you can use them and you don't
+ * need to put query through the Lexer again (after Parser did it).
+ */
+ TokenList getParsedTokens();
+
+ /**
+ * @brief Tells whether most recent parsing was successful.
+ * @return true if parsing was successful, or false otherwise.
+ *
+ * This method tells result for: parse(), parse<T>(), getNextTokenCandidates() and parseExpr().
+ */
+ bool isSuccessful() const;
+
+ /**
+ * @brief Clears parser state.
+ *
+ * Clears any parsed queries, stored tokens, errors, etc.
+ */
+ void reset();
+
+ private:
+
+ /**
+ * @brief Does the actual parsing job.
+ * @param sql Query to be parsed.
+ * @param lookForExpectedToken true if the parsing should be in "look for valid token candidates" mode,
+ * or false for regular mode.
+ * @return true on success, or false on failure.
+ *
+ * Both parse() and getNextTokenCandidates() call this method.
+ */
+ bool parseInternal(const QString &sql, bool lookForExpectedToken);
+
+ /**
+ * @brief Probes token types against the current parser state.
+ * @param pParser Pointer to Lemon parser.
+ *
+ * Probes all token types against current state of the parser. After each probe, the result is stored
+ * and the parser state is restored to as what it was before the probe.
+ *
+ * After all tokens were probed, we have the full information on what tokens are welcome
+ * at this parser state. This information is stored in the acceptedTokens member.
+ */
+ void expectedTokenLookup(void *pParser);
+
+ /**
+ * @brief Initializes Parser's internals.
+ *
+ * Creates internal Lexer and ParserContext.
+ */
+ void init();
+
+ /**
+ * @brief Cleans up Parser's resources.
+ *
+ * Deletes internal Lexer and ParserContext.
+ */
+ void cleanUp();
+
+ /**
+ * @brief Propagates dialect to all AST objects.
+ *
+ * This is called after successful parsing to set the adequate SQLite dialect
+ * in all AST objects.
+ */
+ void fillSqliteDialect();
+
+ /**
+ * @brief Creates Lemon parser.
+ * @return Pointer to Lemon parser.
+ */
+ void* parseAlloc(void *(*mallocProc)(size_t));
+
+ /**
+ * @brief Releases memory of the Lemon parser.
+ * @param p Pointer to Lemon parser.
+ */
+ void parseFree(void *p, void (*freeProc)(void*));
+
+ /**
+ * @brief Invokes next step of Lemon parsing process.
+ * @param yyp Pointer to the Lemon parser.
+ * @param yymajor Lemon token ID (Token::lemonType) of the next token to be parsed.
+ * @param yyminor Next Token object to be parsed.
+ * @param parserContext Common context object for the parsing process.
+ *
+ * This method feeds Lemon parser with next token. This is the major input method
+ * for parsing the query. It's a bridge between the high-level Parser API
+ * and the low-level Lemon parser.
+ */
+ void parse(void *yyp, int yymajor, TokenPtr yyminor, ParserContext* parserContext);
+
+ /**
+ * @brief Enables low-level parser debug messages.
+ * @param stream Stream to write messages to.
+ * @param zPrefix Prefix for all messages.
+ */
+ void parseTrace(FILE *stream, char *zPrefix);
+
+ /**
+ * @brief Copies Lemon parser state.
+ * @param other Input parser state.
+ * @return Copied parser state.
+ */
+ void* parseCopyParserState(void* other);
+
+ /**
+ * @brief Restores Lemon parser state from saved copy.
+ * @param saved Saved copy of Lemon parser state.
+ * @param target Parser state to restore from saved copy.
+ */
+ void parseRestoreParserState(void* saved, void* target);
+
+ /**
+ * @brief Releases memory used for the Lemon parser state copy.
+ * @param other Lemon parser state to be freed.
+ */
+ void parseFreeSavedState(void* other);
+
+ /**
+ * @brief Adds meaningless token into Lemon's parser stack.
+ * @param other Lemon parser.
+ * @param token Token to be added.
+ *
+ * This method is used to add spaces and comments to the Lemon's stack.
+ */
+ void parseAddToken(void* other, TokenPtr token);
+
+ /**
+ * @brief Parser's dialect.
+ */
+ Dialect dialect;
+
+ /**
+ * @brief Flag indicating if the Lemon low-level debug messages are enabled.
+ */
+ bool debugLemon = false;
+
+ /**
+ * @brief Parser's internal Lexer.
+ */
+ Lexer* lexer = nullptr;
+
+ /**
+ * @brief Parser's internal context shared for the all Lemon parsing steps.
+ *
+ * Context is used as an output from Lemon parser. Lemon parser stores error details, token maps,
+ * and others in it.
+ *
+ * On the other side, Parser class puts configuration into the Context, so Lemon
+ * can use it.
+ */
+ ParserContext* context = nullptr;
+
+ /**
+ * @brief List of valid tokens collected by expectedTokenLookup().
+ */
+ TokenList acceptedTokens;
+};
+
+#endif // PARSER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.cpp
new file mode 100644
index 0000000..039c9a5
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.cpp
@@ -0,0 +1,45 @@
+#include "parser_helper_stubs.h"
+#include "ast/sqlitecreatetable.h"
+
+ParserStubAlias::ParserStubAlias(const QString &name, bool asKw)
+{
+ this->name = name;
+ this->asKw = asKw;
+}
+
+ParserIndexedBy::ParserIndexedBy(const QString &name)
+{
+ indexedBy = name;
+}
+
+ParserIndexedBy::ParserIndexedBy(bool notIndexed)
+{
+ this->notIndexedKw = notIndexed;
+}
+
+
+ParserStubInsertOrReplace::ParserStubInsertOrReplace(bool replace)
+{
+ this->replace = replace;
+}
+
+ParserStubInsertOrReplace::ParserStubInsertOrReplace(bool replace, SqliteConflictAlgo orConflict)
+{
+ this->replace = replace;
+ this->orConflict = orConflict;
+}
+
+
+ParserStubExplain::ParserStubExplain(bool explain, bool queryPlan)
+{
+ this->explain = explain;
+ this->queryPlan = queryPlan;
+}
+
+
+ParserDeferSubClause::ParserDeferSubClause(SqliteDeferrable deferrable, SqliteInitially initially)
+{
+ this->initially = initially;
+ this->deferrable = deferrable;
+}
+
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h
new file mode 100644
index 0000000..97a6393
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser_helper_stubs.h
@@ -0,0 +1,118 @@
+#ifndef PARSER_HELPER_STUBS_H
+#define PARSER_HELPER_STUBS_H
+
+#include "parsercontext.h"
+#include "ast/sqlitebegintrans.h"
+#include "ast/sqlitecreatetable.h"
+#include "ast/sqliteconflictalgo.h"
+#include "ast/sqliteselect.h"
+#include "ast/sqliteindexedcolumn.h"
+#include "ast/sqliteforeignkey.h"
+#include "ast/sqliteorderby.h"
+
+#include <QString>
+#include <QList>
+
+/** @file
+ *
+ * This file contains only structures and functions
+ * that are helpful in parsers generated by lemon,
+ * because lemon uses C unions, therefore only primitive
+ * types can be used as data type.
+ * (see %type declarations in *.y files).
+ */
+
+/**
+ * @brief Stores 'dbnm' grammar rule.
+ */
+struct ParserFullName
+{
+ QString name1 = QString::null;
+ QString name2 = QString::null;
+};
+
+/**
+ * @brief Stores <tt>EXPLAIN</tt> and <tt>QUERY PLAN</tt> grammar rules.
+ */
+struct ParserStubExplain
+{
+ ParserStubExplain(bool explain, bool queryPlan);
+
+ bool explain;
+ bool queryPlan;
+};
+
+/**
+ * @brief Stores "<tt>OR</tt> conflict" grammar rules.
+ */
+struct ParserStubInsertOrReplace
+{
+ explicit ParserStubInsertOrReplace(bool replace);
+ ParserStubInsertOrReplace(bool replace, SqliteConflictAlgo orConflict);
+
+ bool replace;
+ SqliteConflictAlgo orConflict;
+};
+
+/**
+ * @brief Stores grammar rules for <tt>BEGIN/END/COMMIT/ROLLBACK</tt> additional parameters.
+ */
+struct ParserStubTransDetails
+{
+ QString name = QString::null;
+ SqliteBeginTrans::Type type = SqliteBeginTrans::Type::null;
+ bool transactionKw = false;
+ bool toKw = false;
+ SqliteConflictAlgo onConflict = SqliteConflictAlgo::null;
+};
+
+typedef QList<SqliteCreateTable::Column*> ParserCreateTableColumnList;
+typedef QList<SqliteCreateTable::Constraint*> ParserCreateTableConstraintList;
+typedef QList<SqliteCreateTable::Column::Constraint*> ParserCreateTableColumnConstraintList;
+typedef QList<SqliteForeignKey::Condition*> ParserFkConditionList;
+typedef QList<SqliteExpr*> ParserExprList;
+typedef QList<SqliteSelect::Core::ResultColumn*> ParserResultColumnList;
+typedef QList<SqliteSelect::Core::JoinSourceOther*> ParserOtherSourceList;
+typedef QList<QString> ParserStringList;
+typedef QList<SqliteOrderBy*> ParserOrderByList;
+typedef QList<SqliteQuery*> ParserQueryList;
+typedef QPair<QString,SqliteExpr*> ParserSetValue;
+typedef QList<ParserSetValue> ParserSetValueList;
+typedef QList<SqliteIndexedColumn*> ParserIndexedColumnList;
+typedef QList<ParserExprList> ParserExprNestedList;
+
+/**
+ * @brief Stores parameters for defferable foreign keys.
+ */
+struct ParserDeferSubClause
+{
+ ParserDeferSubClause(SqliteDeferrable deferrable, SqliteInitially initially);
+
+ SqliteInitially initially;
+ SqliteDeferrable deferrable;
+};
+
+/**
+ * @brief Stores "<tt>AS</tt> aliasName" grammar rule.
+ */
+struct ParserStubAlias
+{
+ ParserStubAlias(const QString& name, bool asKw);
+
+ QString name = QString::null;
+ bool asKw = false;
+};
+
+/**
+ * @brief Stores <tt>NOT INDEXED/INDEXED BY</tt> grammar rules.
+ */
+struct ParserIndexedBy
+{
+ explicit ParserIndexedBy(const QString& name);
+ explicit ParserIndexedBy(bool indexedBy);
+
+ bool notIndexedKw = false;
+ QString indexedBy = QString::null;
+};
+
+#endif // PARSER_HELPER_STUBS_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp
new file mode 100644
index 0000000..7394e75
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.cpp
@@ -0,0 +1,184 @@
+#include "parsercontext.h"
+#include "parsererror.h"
+#include "lexer.h"
+#include <QDebug>
+
+ParserContext::~ParserContext()
+{
+ cleanUp();
+}
+
+void ParserContext::addQuery(SqliteQuery *query)
+{
+ parsedQueries << SqliteQueryPtr(query);
+}
+
+void ParserContext::error(TokenPtr token, const QString &text)
+{
+ if (token->start > -1 && token->end > -1)
+ errors << new ParserError(token, text);
+ else if (managedTokens.size() > 0)
+ errors << new ParserError(managedTokens.last()->start, managedTokens.last()->end + 1, text);
+ else
+ errors << new ParserError(text);
+
+ successful = false;
+}
+
+void ParserContext::error(Token* token, const QString& text)
+{
+ error(getTokenPtr(token), text);
+}
+
+void ParserContext::error(const QString &text)
+{
+ errors << new ParserError(text);
+ successful = false;
+}
+
+void ParserContext::minorErrorAfterLastToken(const QString &text)
+{
+ if (ignoreMinorErrors)
+ return;
+
+ if (managedTokens.isEmpty())
+ {
+ qCritical() << "Tried to report minor error after last token, but there's no tokens!";
+ return;
+ }
+
+ error(managedTokens.last(), text);
+}
+
+void ParserContext::minorErrorBeforeNextToken(const QString &text)
+{
+ if (ignoreMinorErrors)
+ return;
+
+ raiseErrorBeforeNextToken = true;
+ nextTokenError = text;
+}
+
+void ParserContext::errorAfterLastToken(const QString& text)
+{
+ if (managedTokens.isEmpty())
+ {
+ qCritical() << "Tried to report error after last token, but there's no tokens!";
+ return;
+ }
+
+ error(managedTokens.last(), text);
+}
+
+void ParserContext::errorBeforeNextToken(const QString& text)
+{
+ raiseErrorBeforeNextToken = true;
+ nextTokenError = text;
+}
+
+void ParserContext::errorAtToken(const QString& text, int pos)
+{
+ if (managedTokens.isEmpty())
+ {
+ qCritical() << "Tried to report error at token" << pos << ", but there's no tokens!";
+ return;
+ }
+
+ int idx = managedTokens.size() - 1 + pos;
+ if (idx < 0 && idx >= managedTokens.size())
+ {
+ qCritical() << "Tried to report error at token" << pos << ", calculated idx was out of range:" << idx
+ << "(manages tokens size:" << managedTokens.size() << ").";
+ return;
+ }
+
+ error(managedTokens[idx], text);
+}
+
+void ParserContext::flushErrors()
+{
+ if (raiseErrorBeforeNextToken && !ignoreMinorErrors)
+ {
+ if (managedTokens.size() > 0)
+ error(managedTokens.last(), QObject::tr("Incomplete query."));
+ else
+ error(QObject::tr("Incomplete query."));
+
+ nextTokenError = QString::null;
+ raiseErrorBeforeNextToken = false;
+ }
+}
+
+TokenPtr ParserContext::getTokenPtr(Token* token)
+{
+ if (tokenPtrMap.contains(token))
+ return tokenPtrMap[token];
+
+ TokenPtr tokenPtr = Lexer::getEveryTokenTypePtr(token);
+ if (!tokenPtr.isNull())
+ return tokenPtr;
+
+ qWarning() << "No TokenPtr for Token*. Token asked:" << token->toString();
+ return TokenPtr();
+}
+
+TokenList ParserContext::getTokenPtrList(const QList<Token*>& tokens)
+{
+ TokenList resList;
+ foreach (Token* token, tokens)
+ resList << getTokenPtr(token);
+
+ return resList;
+}
+
+void ParserContext::addManagedToken(TokenPtr token)
+{
+ managedTokens << token;
+ tokenPtrMap[token.data()] = token;
+
+ if (raiseErrorBeforeNextToken)
+ {
+ error(token, nextTokenError);
+ nextTokenError = QString::null;
+ raiseErrorBeforeNextToken = false;
+ }
+}
+
+bool ParserContext::isSuccessful() const
+{
+ return successful;
+}
+
+const QList<SqliteQueryPtr>& ParserContext::getQueries()
+{
+ return parsedQueries;
+}
+
+const QList<ParserError *> &ParserContext::getErrors()
+{
+ return errors;
+}
+
+void ParserContext::cleanUp()
+{
+ foreach (ParserError* err, errors)
+ delete err;
+
+ parsedQueries.clear();
+ errors.clear();
+ managedTokens.clear();
+ nextTokenError.clear();
+ tokenPtrMap.clear();
+ raiseErrorBeforeNextToken = false;
+ successful = true;
+}
+
+bool ParserContext::isManagedToken(Token* token)
+{
+ return tokenPtrMap.contains(token);
+}
+
+TokenList ParserContext::getManagedTokens()
+{
+ return managedTokens;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.h b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.h
new file mode 100644
index 0000000..d52c021
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsercontext.h
@@ -0,0 +1,289 @@
+#ifndef PARSERCONTEXT_H
+#define PARSERCONTEXT_H
+
+#include "ast/sqlitequery.h"
+#include "parser.h"
+#include "../dialect.h"
+
+#include <QHash>
+#include <QList>
+#include <QSet>
+
+class ParserError;
+
+/**
+ * @brief Parser context for SQL parsing process
+ * This class should not be used outside of @class Parser.
+ */
+class ParserContext
+{
+ friend class Parser;
+
+ public:
+ /**
+ * @brief Releases all internal resources.
+ */
+ virtual ~ParserContext();
+
+ /**
+ * @brief Adds parsed query to collection of parsed queries.
+ * @param query Parsed query (AST object).
+ *
+ * This is called by Lemon parser.
+ */
+ void addQuery(SqliteQuery* query);
+
+ /**
+ * @brief Stores error at given token with given message.
+ * @param token Token at which the error occurred.
+ * @param text Error message.
+ *
+ * This is called by Lemon parser.
+ */
+ void error(TokenPtr token, const QString& text);
+
+ /**
+ * @overload
+ */
+ void error(Token* token, const QString& text);
+
+ /**
+ * @brief Stores error with given message.
+ * @param text Error message.
+ *
+ * This method is used to report an error not related to specific token,
+ * like when Lemon's stack would get exceeded (which is very unlikely).
+ *
+ * This is called by Lemon parser.
+ *
+ * @overload
+ */
+ void error(const QString& text);
+
+ /**
+ * @brief Stores error with most recently parsed token and given message.
+ * @param text Error message.
+ *
+ * Lemon parser calls it when it found out that the error started at the token before.
+ *
+ * This is just a minor error, so it will be ognored if ignoreMinorErrors is set.
+ */
+ void minorErrorAfterLastToken(const QString& text);
+
+ /**
+ * @brief Marks next token to be parsed with given error message.
+ * @param text Error message.
+ *
+ * Lemon parser calls it when it knows that any next token will be an error.
+ *
+ * This is just a minor error, so it will be ognored if ignoreMinorErrors is set.
+ */
+ void minorErrorBeforeNextToken(const QString& text);
+
+ /**
+ * @brief Stores error message for most recently parsed token.
+ * @param text Error message.
+ *
+ * Lemon parser calls it when critical error occurred at the most recently parsed token.
+ */
+ void errorAfterLastToken(const QString& text);
+
+ /**
+ * @brief Stores error message for the next token to be parsed.
+ * @param text Error message.
+ *
+ * Lemon parser calls it when critical error is about to happen at any next token.
+ */
+ void errorBeforeNextToken(const QString& text);
+
+ /**
+ * @brief Reports parsing error at given token position.
+ * @param text Error message.
+ * @param pos Position relative to after the last token. -1 means the last token, -2 the token before it and so on. -1 is default.
+ *
+ * This method is only useful when we know exactly which token was problematic. If error relates to some already wrapped
+ * syntax rule, it may have many tokens and it's hard to tell which token should we blame, but sometimes it can be calculated.
+ * Anyway, the token with error is reported by the pos argument. If you don't pass it, it means the error is at last token.
+ *
+ * Lemon parser uses it for example when there's a statement <tt>"CREATE TABLE ... (...) WITHOUT ROWID"</tt>. The SQLite grammar
+ * rule says, that the <tt>"ROWID"</tt> at the end is not necessarily the <tt>ROWID</tt> keyword, but it can be any word,
+ * but for now SQLite doesn't understand any other words at that position anyway and returns errors.
+ */
+ void errorAtToken(const QString& text, int pos = -1);
+
+ /**
+ * @brief Flushes pending errors.
+ *
+ * In case the errorBeforeNextToken() was called and no more tokens were feed to the context, then this method flushes
+ * pending error as the error for the last token consumed, but only if minor errors are not ignored.
+ * This happens for example for "SELECT " statement, where it's not correct, but it's a minor error, cause user
+ * might enter more contents afterwards.
+ */
+ void flushErrors();
+
+ /**
+ * @brief Translates token pointer to it's shared pointer instance.
+ * @param token Token pointer to translate.
+ * @return QSharedPointer for the token, or null shared pointer in case of failure.
+ *
+ * This method works basing on internal collection of managed tokens. At each step of parsing, the internal lexer
+ * provides token (in form of shared pointer) and that token is then passed to the Lemon parser (as a pure C++ pointer,
+ * extracted from shared pointer). The very same token is stored in the internal collection of managed tokens (as a shared pointer).
+ * This method allows to get back to the shared pointer.
+ *
+ * This method is necessary to use shared pointers together with Lemon parser, which works on unions and won't be able to use
+ * shared pointers.
+ */
+ TokenPtr getTokenPtr(Token* token);
+
+ /**
+ * @brief Translates list of token pointers to their shared pointer instances.
+ * @param tokens Token pointers to translate.
+ * @return List of QSharedPointers.
+ *
+ * This method is just a convenience way to call getTokenPtr() for a list of pointers.
+ */
+ TokenList getTokenPtrList(const QList<Token*>& tokens);
+
+ /**
+ * @brief Adds token to managed list.
+ * @param token Token to be added to managed tokens.
+ * Tokens managed by context are shared to the Parser, so the API allows to see all parsed tokens.
+ * Some tokens might be created outside of Lexer, so this is the central repository for all tokens to be shared.
+ */
+ void addManagedToken(TokenPtr token);
+
+ /**
+ * @brief Tests whether the token is in the collection of tokens managed by this context.
+ * @param token Token to test.
+ * @return true if the token is managed by this context, or false if not.
+ */
+ bool isManagedToken(Token* token);
+
+ /**
+ * @brief Provides complete list of tokens managed by this context.
+ * @return List of tokens.
+ */
+ TokenList getManagedTokens();
+
+ /**
+ * @brief Tests whether there were any critical errors so far during parsing.
+ * @return true if there were no critical errors, or false otherwise.
+ */
+ bool isSuccessful() const;
+
+ /**
+ * @brief Provides access to list of queries parsed so far.
+ * @return List of parsed AST objects.
+ *
+ * If there was an error, then queries from the list might be incomplete, which means their data members
+ * may still be initialized with their default values. It depends on where the error appeared in the parsed query string.
+ */
+ const QList<SqliteQueryPtr>& getQueries();
+
+ /**
+ * @brief Provides access to all errors occurred so far.
+ * @return List of errors.
+ */
+ const QList<ParserError*>& getErrors();
+
+ /**
+ * @brief Flag indicating if the Lemon parser should setup token collections.
+ *
+ * This setting allows to define whether the Lemon parser should setup token collections for parsed AST objects.
+ * In other words, it tells whether the SqliteStatement::tokens and SqliteStatement::tokensMap should be filled.
+ *
+ * Sometimes it might be worth to disable it to speed up parsig process, but by default it's enabled.
+ */
+ bool setupTokens = true;
+
+ /**
+ * @brief Flag inficating if the Lemon parser should exectute code for the grammar rules.
+ *
+ * This setting allows to define whether the Lemon parser should execute the code associated with rules.
+ * Disabling it will cause no AST objects to be produced, but it can be used to find out syntax errors.
+ * If you don't need AST objects (output from parsing), then you can turn this off to speed up Lemon parser.
+ *
+ * The Parser class for example turns it of when it probes for next valid token candidates. In that case
+ * no AST output objects are used, just information whether the next candidate is valid or not.
+ */
+ bool executeRules = true;
+
+ /**
+ * @brief Flag indicating if the Lemon parser should perform "fallback" logic.
+ *
+ * The "fallback" login in the Lemon parser is used when the input token is one of the keywords and it failed
+ * at that step. Then the "fallback" steps in and converts keyword token into the "ID" token, which represents
+ * a name of any object in the database (not necessarily existing one). Then the Lemon parser retries with
+ * that ID token and if that fails to fulfill the syntax rules too, then the error is reported.
+ *
+ * This is enabled by default, cause SQLite usually uses that too. It is for example disabled when looking
+ * for the next valid token candidate in Parser::getNextTokenCandidates(), cause for that case we need
+ * very strict token matching against the syntax.
+ */
+ bool doFallbacks = true;
+
+ /**
+ * @brief Flag indicating if minor errors should be ignored by the Lemon parser.
+ *
+ * See description of Parser::parse() for details.
+ */
+ bool ignoreMinorErrors = false;
+
+ /**
+ * @brief Dialect used for the parsing.
+ *
+ * This is used by the Lemon parser in various situations, like for example when it strips the object name
+ * from it's wrapping characters ([], "", ``) - that depends on the dialect.
+ */
+ Dialect dialect;
+
+ private:
+ /**
+ * @brief Clears all internal containers and deletes error objects.
+ */
+ void cleanUp();
+
+ /**
+ * @brief List of parsed AST objects.
+ */
+ QList<SqliteQueryPtr> parsedQueries;
+
+ /**
+ * @brief Tokens managed by this context.
+ */
+ TokenList managedTokens;
+
+ /**
+ * @brief Mapping from token pointer to it's shared pointer instance.
+ */
+ QHash<Token*, TokenPtr> tokenPtrMap;
+
+ /**
+ * @brief Flag indicating successful or failure parsing.
+ *
+ * Changed to false when the error was reported.
+ */
+ bool successful = true;
+
+ /**
+ * @brief List of errors reported by Lemon.
+ */
+ QList<ParserError*> errors;
+
+ /**
+ * @brief Flag indicating that the next token should raise an error.
+ *
+ * This is set by errorBeforeNextToken() and minorErrorBeforeNextToken().
+ */
+ bool raiseErrorBeforeNextToken = false;
+
+ /**
+ * @brief Error to be used for the error at next token.
+ *
+ * Defined by errorBeforeNextToken() and minorErrorBeforeNextToken().
+ */
+ QString nextTokenError;
+};
+
+#endif // PARSERCONTEXT_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.cpp
new file mode 100644
index 0000000..22fc531
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.cpp
@@ -0,0 +1,44 @@
+#include "parsererror.h"
+#include "token.h"
+
+ParserError::ParserError(TokenPtr token, const QString &text)
+{
+ if (token)
+ {
+ start = token->start;
+ end = token->end;
+ }
+ message = text;
+}
+
+ParserError::ParserError(qint64 start, qint64 end, const QString& text) :
+ message(text),
+ start(start),
+ end(end)
+{
+}
+
+ParserError::ParserError(const QString &text)
+{
+ message = text;
+}
+
+QString &ParserError::getMessage()
+{
+ return message;
+}
+
+qint64 ParserError::getFrom()
+{
+ return start;
+}
+
+qint64 ParserError::getTo()
+{
+ return end;
+}
+
+QString ParserError::toString()
+{
+ return QString("%1: %2").arg(start).arg(message);
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.h b/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.h
new file mode 100644
index 0000000..673f030
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parsererror.h
@@ -0,0 +1,80 @@
+#ifndef PARSERERROR_H
+#define PARSERERROR_H
+
+#include "coreSQLiteStudio_global.h"
+#include "parser/token.h"
+#include <QString>
+
+/**
+ * @brief Class representing error during SQL parsing.
+ *
+ * It provides error message and position at which the error occurred.
+ */
+class API_EXPORT ParserError
+{
+ public:
+ /**
+ * @brief Creates error for given token and message.
+ * @param token Token that the error occurred at.
+ * @param text Error message.
+ */
+ ParserError(TokenPtr token, const QString& text);
+
+ /**
+ * @brief Creates error with given range and message.
+ * @param start Position where the error starts.
+ * @param end Position where the error ends.
+ * @param text Error message.
+ */
+ ParserError(qint64 start, qint64 end, const QString& text);
+
+ /**
+ * @brief Creates global error with given message.
+ * @param text Error message.
+ *
+ * Global errors are not related to any token or position.
+ */
+ explicit ParserError(const QString& text);
+
+ /**
+ * @brief Provides error message.
+ * @return Error message.
+ */
+ QString& getMessage();
+
+ /**
+ * @brief Provides start position of the error.
+ * @return Character position, or -1 if the error is not related to any position (global error).
+ */
+ qint64 getFrom();
+
+ /**
+ * @brief Provides end position of the error.
+ * @return Character position, or -1 if the error is not related to any position (global error).
+ */
+ qint64 getTo();
+
+ /**
+ * @brief Serializes error to readable string.
+ * @return Start position and error message in form: <tt>"position: message"</tt>.
+ */
+ QString toString();
+
+ private:
+ /**
+ * @brief Error message.
+ */
+ QString message = QString::null;
+
+ /**
+ * @brief Error start position.
+ */
+ qint64 start = -1;
+
+ /**
+ * @brief Error end position.
+ */
+ qint64 end = -1;
+};
+
+#endif // PARSERERROR_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.sh b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.sh
new file mode 100755
index 0000000..3df47e1
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/run_lemon.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+#lemon -l -q -s sqlite3_parse.y
+lemon -l -q sqlite3_parse.y
+mv sqlite3_parse.c sqlite3_parse.cpp
+
+lemon -l -q sqlite2_parse.y
+mv sqlite2_parse.c sqlite2_parse.cpp
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp
new file mode 100644
index 0000000..7fc9edc
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.cpp
@@ -0,0 +1,4650 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+**
+** This version of "lempar.c" is modified, slightly, for use by SQLite.
+** The only modifications are the addition of a couple of NEVER()
+** macros to disable tests that are needed in the case of a general
+** LALR(1) grammar but which are always false in the
+** specific grammar used by SQLite.
+*/
+/* First off, code is included that follows the "include" declaration
+** in the input grammar file. */
+#include <stdio.h>
+
+#include "token.h"
+#include "parsercontext.h"
+#include "parser/ast/sqlitealtertable.h"
+#include "parser/ast/sqliteanalyze.h"
+#include "parser/ast/sqliteattach.h"
+#include "parser/ast/sqlitebegintrans.h"
+#include "parser/ast/sqlitecommittrans.h"
+#include "parser/ast/sqlitecopy.h"
+#include "parser/ast/sqlitecreateindex.h"
+#include "parser/ast/sqlitecreatetable.h"
+#include "parser/ast/sqlitecreatetrigger.h"
+#include "parser/ast/sqlitecreateview.h"
+#include "parser/ast/sqlitecreatevirtualtable.h"
+#include "parser/ast/sqlitedelete.h"
+#include "parser/ast/sqlitedetach.h"
+#include "parser/ast/sqlitedropindex.h"
+#include "parser/ast/sqlitedroptable.h"
+#include "parser/ast/sqlitedroptrigger.h"
+#include "parser/ast/sqlitedropview.h"
+#include "parser/ast/sqliteemptyquery.h"
+#include "parser/ast/sqliteinsert.h"
+#include "parser/ast/sqlitepragma.h"
+#include "parser/ast/sqlitereindex.h"
+#include "parser/ast/sqliterelease.h"
+#include "parser/ast/sqliterollback.h"
+#include "parser/ast/sqlitesavepoint.h"
+#include "parser/ast/sqliteselect.h"
+#include "parser/ast/sqliteupdate.h"
+#include "parser/ast/sqlitevacuum.h"
+#include "parser/ast/sqliteexpr.h"
+#include "parser/ast/sqlitecolumntype.h"
+#include "parser/ast/sqliteconflictalgo.h"
+#include "parser/ast/sqlitesortorder.h"
+#include "parser/ast/sqliteindexedcolumn.h"
+#include "parser/ast/sqliteforeignkey.h"
+#include "parser_helper_stubs.h"
+#include "common/utils_sql.h"
+#include <QObject>
+#include <QDebug>
+
+#define assert(X) Q_ASSERT(X)
+#define UNUSED_PARAMETER(X) (void)(X)
+#define DONT_INHERIT_TOKENS(X) noTokenInheritanceFields << X
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** sqlite2_parseTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is sqlite2_parseTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
+** sqlite2_parseARG_SDECL A static variable declaration for the %extra_argument
+** sqlite2_parseARG_PDECL A parameter declaration for the %extra_argument
+** sqlite2_parseARG_STORE Code to store %extra_argument into yypParser
+** sqlite2_parseARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+#define YYCODETYPE unsigned char
+#define YYNOCODE 241
+#define YYACTIONTYPE unsigned short int
+#define sqlite2_parseTOKENTYPE Token*
+typedef union {
+ int yyinit;
+ sqlite2_parseTOKENTYPE yy0;
+ ParserCreateTableConstraintList* yy13;
+ SqliteSelect::Core::JoinSource* yy31;
+ ParserStubAlias* yy40;
+ SqliteExpr::LikeOp* yy41;
+ ParserCreateTableColumnList* yy42;
+ SqliteColumnType* yy57;
+ ParserIndexedColumnList* yy63;
+ QVariant* yy69;
+ SqliteCreateTrigger::Scope* yy83;
+ ParserStubExplain* yy91;
+ ParserFullName* yy120;
+ SqliteSelect::Core::SingleSource* yy121;
+ ParserOtherSourceList* yy131;
+ SqliteCreateTable::Column* yy147;
+ SqliteSelect::Core* yy150;
+ SqliteCreateTrigger::Event* yy151;
+ SqliteSelect* yy153;
+ SqliteForeignKey::Condition* yy187;
+ SqliteExpr* yy192;
+ ParserSetValueList* yy201;
+ SqliteQuery* yy203;
+ ParserStringList* yy207;
+ ParserResultColumnList* yy213;
+ SqliteSelect::Core::JoinOp* yy221;
+ int* yy226;
+ ParserExprList* yy231;
+ ParserOrderByList* yy243;
+ ParserFkConditionList* yy264;
+ ParserQueryList* yy270;
+ bool* yy291;
+ SqliteCreateTable::Column::Constraint* yy304;
+ SqliteInitially* yy312;
+ QString* yy319;
+ SqliteLimit* yy324;
+ ParserDeferSubClause* yy329;
+ ParserStubInsertOrReplace* yy344;
+ ParserCreateTableColumnConstraintList* yy371;
+ SqliteCreateTrigger::Time* yy372;
+ SqliteSelect::CompoundOperator* yy382;
+ SqliteSortOrder* yy389;
+ ParserStubTransDetails* yy404;
+ SqliteCreateTable::Constraint* yy406;
+ SqliteConflictAlgo* yy418;
+ SqliteForeignKey::Condition::Reaction* yy424;
+ SqliteIndexedColumn* yy428;
+ SqliteSelect::Core::JoinConstraint* yy455;
+} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
+#define YYSTACKDEPTH 100
+#endif
+#define sqlite2_parseARG_SDECL ParserContext* parserContext;
+#define sqlite2_parseARG_PDECL ,ParserContext* parserContext
+#define sqlite2_parseARG_FETCH ParserContext* parserContext = yypParser->parserContext
+#define sqlite2_parseARG_STORE yypParser->parserContext = parserContext
+#define YYNSTATE 584
+#define YYNRULE 352
+#define YYFALLBACK 1
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+#define GET_CONTEXT yyParser* yypParser = pParser; sqlite2_parseARG_FETCH
+
+/* The yyzerominor constant is used to initialize instances of
+** YYMINORTYPE objects to zero. */
+static const YYMINORTYPE yyzerominor = { 0 };
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage. For production
+** code the yytestcase() macro should be turned off. But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+#define YY_ACTTAB_COUNT (1697)
+static const YYACTIONTYPE yy_action[] = {
+ /* 0 */ 338, 191, 186, 242, 476, 511, 576, 193, 332, 16,
+ /* 10 */ 511, 384, 189, 322, 239, 519, 518, 570, 337, 450,
+ /* 20 */ 15, 851, 125, 58, 575, 179, 851, 574, 63, 142,
+ /* 30 */ 401, 581, 328, 27, 84, 569, 114, 322, 573, 519,
+ /* 40 */ 518, 851, 851, 36, 851, 851, 851, 851, 851, 851,
+ /* 50 */ 851, 851, 851, 851, 851, 851, 851, 851, 851, 33,
+ /* 60 */ 34, 851, 851, 851, 851, 320, 379, 35, 240, 238,
+ /* 70 */ 121, 556, 291, 251, 57, 7, 217, 577, 265, 264,
+ /* 80 */ 523, 179, 555, 336, 335, 338, 569, 549, 548, 550,
+ /* 90 */ 271, 569, 10, 724, 199, 297, 203, 489, 459, 332,
+ /* 100 */ 568, 567, 451, 253, 158, 523, 449, 444, 443, 337,
+ /* 110 */ 187, 870, 266, 187, 580, 517, 168, 328, 505, 343,
+ /* 120 */ 142, 235, 490, 108, 101, 489, 523, 164, 36, 531,
+ /* 130 */ 187, 13, 523, 252, 234, 547, 236, 119, 340, 232,
+ /* 140 */ 339, 120, 216, 155, 33, 34, 481, 547, 322, 215,
+ /* 150 */ 519, 518, 35, 714, 456, 477, 320, 367, 547, 478,
+ /* 160 */ 7, 714, 400, 321, 251, 523, 714, 563, 336, 335,
+ /* 170 */ 500, 553, 549, 548, 550, 188, 465, 500, 401, 466,
+ /* 180 */ 366, 365, 552, 364, 293, 435, 40, 40, 40, 39,
+ /* 190 */ 523, 562, 60, 255, 714, 569, 714, 714, 852, 570,
+ /* 200 */ 271, 714, 502, 852, 500, 714, 570, 714, 714, 714,
+ /* 210 */ 714, 523, 569, 178, 531, 422, 13, 523, 45, 46,
+ /* 220 */ 330, 43, 43, 530, 530, 223, 852, 852, 44, 44,
+ /* 230 */ 44, 44, 42, 42, 42, 42, 41, 41, 40, 40,
+ /* 240 */ 40, 39, 199, 297, 203, 55, 236, 92, 340, 232,
+ /* 250 */ 339, 120, 216, 500, 106, 570, 268, 19, 187, 215,
+ /* 260 */ 500, 105, 553, 42, 42, 42, 42, 41, 41, 40,
+ /* 270 */ 40, 40, 39, 552, 41, 41, 40, 40, 40, 39,
+ /* 280 */ 852, 3, 568, 567, 187, 852, 512, 500, 219, 568,
+ /* 290 */ 567, 17, 496, 156, 322, 345, 519, 518, 569, 292,
+ /* 300 */ 45, 46, 330, 43, 43, 530, 530, 223, 852, 852,
+ /* 310 */ 44, 44, 44, 44, 42, 42, 42, 42, 41, 41,
+ /* 320 */ 40, 40, 40, 39, 547, 533, 852, 100, 308, 306,
+ /* 330 */ 305, 852, 448, 447, 418, 418, 316, 245, 568, 567,
+ /* 340 */ 304, 937, 122, 344, 1, 582, 45, 46, 330, 43,
+ /* 350 */ 43, 530, 530, 223, 852, 852, 44, 44, 44, 44,
+ /* 360 */ 42, 42, 42, 42, 41, 41, 40, 40, 40, 39,
+ /* 370 */ 338, 442, 45, 46, 330, 43, 43, 530, 530, 223,
+ /* 380 */ 524, 569, 44, 44, 44, 44, 42, 42, 42, 42,
+ /* 390 */ 41, 41, 40, 40, 40, 39, 5, 9, 524, 781,
+ /* 400 */ 220, 324, 328, 167, 45, 46, 330, 43, 43, 530,
+ /* 410 */ 530, 223, 781, 36, 44, 44, 44, 44, 42, 42,
+ /* 420 */ 42, 42, 41, 41, 40, 40, 40, 39, 8, 33,
+ /* 430 */ 34, 274, 387, 435, 547, 388, 237, 35, 774, 421,
+ /* 440 */ 60, 14, 219, 569, 250, 7, 774, 437, 441, 169,
+ /* 450 */ 523, 524, 569, 336, 335, 285, 781, 549, 548, 550,
+ /* 460 */ 44, 44, 44, 44, 42, 42, 42, 42, 41, 41,
+ /* 470 */ 40, 40, 40, 39, 332, 523, 332, 425, 470, 774,
+ /* 480 */ 560, 774, 774, 850, 337, 426, 337, 455, 850, 613,
+ /* 490 */ 774, 181, 774, 774, 774, 142, 523, 142, 31, 531,
+ /* 500 */ 614, 13, 523, 850, 850, 850, 850, 850, 850, 850,
+ /* 510 */ 850, 850, 850, 850, 850, 850, 850, 850, 850, 850,
+ /* 520 */ 850, 850, 850, 850, 850, 850, 850, 852, 500, 460,
+ /* 530 */ 357, 320, 852, 318, 75, 570, 401, 570, 311, 251,
+ /* 540 */ 569, 251, 446, 445, 570, 358, 359, 45, 46, 330,
+ /* 550 */ 43, 43, 530, 530, 223, 852, 852, 44, 44, 44,
+ /* 560 */ 44, 42, 42, 42, 42, 41, 41, 40, 40, 40,
+ /* 570 */ 39, 338, 45, 46, 330, 43, 43, 530, 530, 223,
+ /* 580 */ 615, 570, 44, 44, 44, 44, 42, 42, 42, 42,
+ /* 590 */ 41, 41, 40, 40, 40, 39, 185, 184, 497, 782,
+ /* 600 */ 199, 297, 203, 328, 360, 538, 96, 488, 97, 570,
+ /* 610 */ 103, 500, 782, 436, 36, 570, 187, 225, 568, 567,
+ /* 620 */ 568, 567, 332, 354, 540, 539, 294, 568, 567, 570,
+ /* 630 */ 33, 34, 337, 356, 482, 355, 569, 85, 35, 759,
+ /* 640 */ 532, 111, 70, 78, 487, 483, 7, 759, 90, 494,
+ /* 650 */ 508, 523, 493, 160, 336, 335, 782, 528, 549, 548,
+ /* 660 */ 550, 532, 440, 434, 568, 567, 118, 54, 332, 919,
+ /* 670 */ 214, 100, 308, 306, 305, 75, 523, 333, 337, 571,
+ /* 680 */ 759, 529, 759, 759, 304, 48, 177, 522, 32, 142,
+ /* 690 */ 30, 759, 568, 567, 759, 759, 159, 523, 568, 567,
+ /* 700 */ 531, 464, 13, 523, 45, 46, 330, 43, 43, 530,
+ /* 710 */ 530, 223, 568, 567, 44, 44, 44, 44, 42, 42,
+ /* 720 */ 42, 42, 41, 41, 40, 40, 40, 39, 463, 570,
+ /* 730 */ 498, 919, 570, 323, 514, 570, 222, 45, 46, 330,
+ /* 740 */ 43, 43, 530, 530, 223, 393, 392, 44, 44, 44,
+ /* 750 */ 44, 42, 42, 42, 42, 41, 41, 40, 40, 40,
+ /* 760 */ 39, 45, 46, 330, 43, 43, 530, 530, 223, 540,
+ /* 770 */ 539, 44, 44, 44, 44, 42, 42, 42, 42, 41,
+ /* 780 */ 41, 40, 40, 40, 39, 583, 1, 45, 46, 330,
+ /* 790 */ 43, 43, 530, 530, 223, 267, 475, 44, 44, 44,
+ /* 800 */ 44, 42, 42, 42, 42, 41, 41, 40, 40, 40,
+ /* 810 */ 39, 434, 568, 567, 420, 568, 567, 163, 568, 567,
+ /* 820 */ 570, 110, 218, 45, 46, 330, 43, 43, 530, 530,
+ /* 830 */ 223, 28, 468, 44, 44, 44, 44, 42, 42, 42,
+ /* 840 */ 42, 41, 41, 40, 40, 40, 39, 570, 547, 45,
+ /* 850 */ 46, 330, 43, 43, 530, 530, 223, 570, 212, 44,
+ /* 860 */ 44, 44, 44, 42, 42, 42, 42, 41, 41, 40,
+ /* 870 */ 40, 40, 39, 46, 330, 43, 43, 530, 530, 223,
+ /* 880 */ 527, 526, 44, 44, 44, 44, 42, 42, 42, 42,
+ /* 890 */ 41, 41, 40, 40, 40, 39, 338, 330, 43, 43,
+ /* 900 */ 530, 530, 223, 568, 567, 44, 44, 44, 44, 42,
+ /* 910 */ 42, 42, 42, 41, 41, 40, 40, 40, 39, 570,
+ /* 920 */ 525, 570, 64, 859, 88, 424, 198, 391, 328, 520,
+ /* 930 */ 568, 567, 357, 570, 516, 164, 569, 380, 12, 36,
+ /* 940 */ 568, 567, 569, 164, 502, 25, 570, 358, 275, 172,
+ /* 950 */ 171, 170, 391, 256, 569, 33, 34, 310, 66, 389,
+ /* 960 */ 390, 287, 76, 35, 104, 395, 547, 484, 561, 79,
+ /* 970 */ 452, 7, 862, 395, 547, 455, 523, 338, 80, 336,
+ /* 980 */ 335, 213, 480, 549, 548, 550, 75, 312, 396, 398,
+ /* 990 */ 570, 397, 293, 479, 570, 380, 396, 398, 259, 397,
+ /* 1000 */ 293, 523, 568, 567, 568, 567, 276, 538, 10, 328,
+ /* 1010 */ 4, 289, 474, 490, 570, 473, 568, 567, 23, 290,
+ /* 1020 */ 36, 65, 523, 431, 284, 531, 532, 13, 523, 568,
+ /* 1030 */ 567, 497, 570, 584, 439, 332, 33, 34, 490, 317,
+ /* 1040 */ 162, 489, 535, 570, 35, 337, 570, 532, 570, 179,
+ /* 1050 */ 307, 53, 7, 471, 52, 345, 139, 523, 338, 569,
+ /* 1060 */ 336, 335, 179, 302, 549, 548, 550, 495, 75, 303,
+ /* 1070 */ 413, 547, 569, 568, 567, 570, 254, 568, 567, 325,
+ /* 1080 */ 262, 209, 523, 272, 570, 18, 569, 361, 160, 570,
+ /* 1090 */ 328, 569, 515, 261, 407, 413, 51, 568, 567, 570,
+ /* 1100 */ 522, 36, 569, 523, 192, 582, 531, 10, 13, 523,
+ /* 1110 */ 99, 338, 489, 730, 569, 568, 567, 33, 34, 407,
+ /* 1120 */ 503, 500, 456, 403, 570, 35, 568, 567, 376, 568,
+ /* 1130 */ 567, 568, 567, 7, 211, 456, 570, 490, 523, 570,
+ /* 1140 */ 489, 336, 335, 328, 570, 549, 548, 550, 403, 497,
+ /* 1150 */ 730, 730, 404, 376, 36, 371, 500, 108, 568, 567,
+ /* 1160 */ 124, 101, 234, 523, 486, 279, 82, 568, 567, 2,
+ /* 1170 */ 33, 34, 568, 567, 497, 569, 197, 301, 35, 368,
+ /* 1180 */ 69, 75, 568, 567, 523, 492, 7, 531, 666, 13,
+ /* 1190 */ 523, 523, 338, 423, 336, 335, 417, 73, 549, 548,
+ /* 1200 */ 550, 350, 485, 570, 568, 567, 570, 568, 567, 22,
+ /* 1210 */ 491, 570, 21, 67, 371, 179, 523, 6, 258, 568,
+ /* 1220 */ 567, 219, 568, 567, 328, 569, 405, 568, 567, 570,
+ /* 1230 */ 255, 569, 399, 106, 394, 36, 215, 523, 71, 500,
+ /* 1240 */ 531, 368, 13, 523, 416, 860, 260, 386, 570, 415,
+ /* 1250 */ 338, 33, 34, 269, 544, 543, 205, 570, 204, 35,
+ /* 1260 */ 108, 350, 409, 81, 570, 385, 569, 7, 502, 507,
+ /* 1270 */ 245, 496, 523, 182, 50, 336, 335, 570, 569, 549,
+ /* 1280 */ 548, 550, 328, 160, 338, 281, 568, 567, 456, 568,
+ /* 1290 */ 567, 570, 381, 36, 568, 567, 115, 523, 278, 277,
+ /* 1300 */ 570, 351, 570, 363, 353, 187, 352, 49, 411, 33,
+ /* 1310 */ 34, 406, 568, 567, 538, 160, 328, 35, 523, 174,
+ /* 1320 */ 157, 531, 286, 13, 523, 7, 862, 36, 185, 184,
+ /* 1330 */ 523, 568, 567, 336, 335, 179, 362, 549, 548, 550,
+ /* 1340 */ 568, 567, 180, 33, 34, 569, 569, 568, 567, 383,
+ /* 1350 */ 74, 35, 202, 377, 296, 523, 540, 539, 241, 7,
+ /* 1360 */ 568, 567, 569, 579, 523, 374, 257, 336, 335, 342,
+ /* 1370 */ 112, 549, 548, 550, 568, 567, 523, 346, 201, 531,
+ /* 1380 */ 200, 13, 523, 568, 567, 568, 567, 569, 569, 523,
+ /* 1390 */ 542, 544, 543, 536, 544, 543, 566, 332, 263, 544,
+ /* 1400 */ 543, 332, 565, 373, 309, 544, 543, 337, 456, 564,
+ /* 1410 */ 523, 337, 341, 531, 332, 13, 523, 501, 77, 370,
+ /* 1420 */ 11, 559, 146, 196, 337, 378, 457, 332, 408, 558,
+ /* 1430 */ 557, 270, 332, 569, 332, 144, 554, 337, 187, 332,
+ /* 1440 */ 551, 546, 337, 17, 337, 47, 332, 332, 151, 337,
+ /* 1450 */ 227, 538, 228, 150, 538, 152, 337, 337, 229, 538,
+ /* 1460 */ 161, 24, 522, 226, 319, 538, 522, 224, 249, 334,
+ /* 1470 */ 59, 545, 220, 332, 332, 332, 39, 521, 37, 522,
+ /* 1480 */ 332, 332, 183, 337, 337, 337, 29, 109, 332, 510,
+ /* 1490 */ 337, 337, 522, 572, 143, 149, 145, 522, 337, 522,
+ /* 1500 */ 332, 248, 247, 569, 522, 332, 332, 570, 332, 246,
+ /* 1510 */ 337, 522, 522, 332, 332, 337, 337, 513, 337, 107,
+ /* 1520 */ 83, 141, 332, 337, 337, 472, 133, 132, 454, 140,
+ /* 1530 */ 56, 332, 337, 244, 131, 148, 453, 430, 522, 522,
+ /* 1540 */ 522, 337, 429, 147, 428, 522, 522, 332, 332, 534,
+ /* 1550 */ 326, 332, 130, 522, 332, 243, 332, 337, 337, 569,
+ /* 1560 */ 569, 337, 427, 419, 337, 522, 337, 98, 129, 127,
+ /* 1570 */ 522, 522, 135, 522, 332, 134, 332, 136, 522, 522,
+ /* 1580 */ 195, 332, 372, 314, 337, 207, 337, 522, 95, 288,
+ /* 1590 */ 569, 337, 94, 337, 206, 138, 522, 137, 298, 194,
+ /* 1600 */ 20, 369, 128, 414, 61, 504, 68, 153, 499, 569,
+ /* 1610 */ 102, 93, 522, 522, 315, 569, 522, 469, 569, 522,
+ /* 1620 */ 569, 522, 432, 210, 569, 300, 91, 569, 123, 72,
+ /* 1630 */ 166, 402, 569, 569, 117, 569, 89, 295, 283, 522,
+ /* 1640 */ 569, 522, 375, 382, 280, 331, 522, 569, 522, 221,
+ /* 1650 */ 208, 176, 569, 87, 86, 569, 347, 175, 116, 569,
+ /* 1660 */ 569, 569, 349, 173, 113, 126, 233, 541, 230, 154,
+ /* 1670 */ 537, 329, 509, 506, 458, 410, 273, 299, 470, 282,
+ /* 1680 */ 190, 348, 467, 462, 461, 438, 38, 165, 938, 62,
+ /* 1690 */ 938, 327, 231, 578, 433, 938, 412,
+};
+static const YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 4, 8, 195, 10, 80, 25, 5, 14, 156, 202,
+ /* 10 */ 30, 41, 19, 113, 21, 115, 116, 4, 166, 4,
+ /* 20 */ 79, 25, 81, 34, 23, 156, 30, 26, 35, 177,
+ /* 30 */ 37, 72, 36, 53, 54, 166, 43, 113, 37, 115,
+ /* 40 */ 116, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 50 */ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ /* 60 */ 64, 65, 66, 67, 68, 213, 96, 71, 75, 76,
+ /* 70 */ 77, 16, 220, 221, 85, 79, 156, 76, 63, 64,
+ /* 80 */ 84, 156, 27, 87, 88, 4, 166, 91, 92, 93,
+ /* 90 */ 47, 166, 79, 80, 101, 102, 103, 84, 229, 156,
+ /* 100 */ 87, 88, 87, 110, 161, 109, 91, 92, 93, 166,
+ /* 110 */ 117, 141, 187, 117, 148, 80, 161, 36, 80, 153,
+ /* 120 */ 177, 93, 109, 85, 31, 112, 130, 161, 47, 133,
+ /* 130 */ 117, 135, 136, 90, 106, 192, 93, 94, 95, 96,
+ /* 140 */ 97, 98, 99, 13, 63, 64, 65, 192, 113, 106,
+ /* 150 */ 115, 116, 71, 72, 229, 114, 213, 191, 192, 118,
+ /* 160 */ 79, 80, 21, 220, 221, 84, 85, 80, 87, 88,
+ /* 170 */ 4, 7, 91, 92, 93, 32, 90, 4, 37, 93,
+ /* 180 */ 214, 215, 18, 217, 218, 156, 65, 66, 67, 68,
+ /* 190 */ 109, 162, 163, 100, 113, 166, 115, 116, 25, 4,
+ /* 200 */ 47, 120, 156, 30, 4, 124, 4, 126, 127, 128,
+ /* 210 */ 129, 130, 166, 184, 133, 186, 135, 136, 45, 46,
+ /* 220 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 230 */ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ /* 240 */ 67, 68, 101, 102, 103, 79, 93, 85, 95, 96,
+ /* 250 */ 97, 98, 99, 87, 81, 4, 210, 79, 117, 106,
+ /* 260 */ 87, 80, 7, 59, 60, 61, 62, 63, 64, 65,
+ /* 270 */ 66, 67, 68, 18, 63, 64, 65, 66, 67, 68,
+ /* 280 */ 25, 79, 87, 88, 117, 30, 84, 87, 156, 87,
+ /* 290 */ 88, 129, 119, 161, 113, 22, 115, 116, 166, 132,
+ /* 300 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 310 */ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ /* 320 */ 65, 66, 67, 68, 192, 130, 25, 94, 95, 96,
+ /* 330 */ 97, 30, 91, 92, 83, 84, 204, 205, 87, 88,
+ /* 340 */ 107, 149, 150, 151, 152, 72, 45, 46, 47, 48,
+ /* 350 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 360 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 370 */ 4, 156, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 380 */ 5, 166, 55, 56, 57, 58, 59, 60, 61, 62,
+ /* 390 */ 63, 64, 65, 66, 67, 68, 79, 48, 23, 72,
+ /* 400 */ 99, 26, 36, 161, 45, 46, 47, 48, 49, 50,
+ /* 410 */ 51, 52, 85, 47, 55, 56, 57, 58, 59, 60,
+ /* 420 */ 61, 62, 63, 64, 65, 66, 67, 68, 79, 63,
+ /* 430 */ 64, 82, 6, 156, 192, 9, 159, 71, 72, 162,
+ /* 440 */ 163, 125, 156, 166, 164, 79, 80, 167, 168, 169,
+ /* 450 */ 84, 76, 166, 87, 88, 29, 129, 91, 92, 93,
+ /* 460 */ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ /* 470 */ 65, 66, 67, 68, 156, 109, 156, 180, 181, 113,
+ /* 480 */ 173, 115, 116, 25, 166, 188, 166, 180, 30, 82,
+ /* 490 */ 124, 205, 126, 127, 128, 177, 130, 177, 139, 133,
+ /* 500 */ 82, 135, 136, 45, 46, 47, 48, 49, 50, 51,
+ /* 510 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ /* 520 */ 62, 63, 64, 65, 66, 67, 68, 25, 4, 80,
+ /* 530 */ 156, 213, 30, 213, 85, 4, 37, 4, 220, 221,
+ /* 540 */ 166, 221, 91, 92, 4, 171, 172, 45, 46, 47,
+ /* 550 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 560 */ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ /* 570 */ 68, 4, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 580 */ 82, 4, 55, 56, 57, 58, 59, 60, 61, 62,
+ /* 590 */ 63, 64, 65, 66, 67, 68, 63, 64, 167, 72,
+ /* 600 */ 101, 102, 103, 36, 230, 231, 42, 85, 44, 4,
+ /* 610 */ 88, 87, 85, 89, 47, 4, 117, 85, 87, 88,
+ /* 620 */ 87, 88, 156, 90, 91, 92, 156, 87, 88, 4,
+ /* 630 */ 63, 64, 166, 100, 203, 102, 166, 82, 71, 72,
+ /* 640 */ 109, 82, 78, 177, 122, 123, 79, 80, 82, 109,
+ /* 650 */ 85, 84, 112, 222, 87, 88, 129, 21, 91, 92,
+ /* 660 */ 93, 130, 80, 86, 87, 88, 100, 85, 156, 10,
+ /* 670 */ 80, 94, 95, 96, 97, 85, 109, 211, 166, 74,
+ /* 680 */ 113, 93, 115, 116, 107, 120, 216, 221, 138, 177,
+ /* 690 */ 140, 124, 87, 88, 127, 128, 79, 130, 87, 88,
+ /* 700 */ 133, 11, 135, 136, 45, 46, 47, 48, 49, 50,
+ /* 710 */ 51, 52, 87, 88, 55, 56, 57, 58, 59, 60,
+ /* 720 */ 61, 62, 63, 64, 65, 66, 67, 68, 38, 4,
+ /* 730 */ 119, 72, 4, 221, 109, 4, 224, 45, 46, 47,
+ /* 740 */ 48, 49, 50, 51, 52, 39, 40, 55, 56, 57,
+ /* 750 */ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ /* 760 */ 68, 45, 46, 47, 48, 49, 50, 51, 52, 91,
+ /* 770 */ 92, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ /* 780 */ 64, 65, 66, 67, 68, 151, 152, 45, 46, 47,
+ /* 790 */ 48, 49, 50, 51, 52, 105, 80, 55, 56, 57,
+ /* 800 */ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ /* 810 */ 68, 86, 87, 88, 83, 87, 88, 161, 87, 88,
+ /* 820 */ 4, 85, 80, 45, 46, 47, 48, 49, 50, 51,
+ /* 830 */ 52, 139, 104, 55, 56, 57, 58, 59, 60, 61,
+ /* 840 */ 62, 63, 64, 65, 66, 67, 68, 4, 192, 45,
+ /* 850 */ 46, 47, 48, 49, 50, 51, 52, 4, 80, 55,
+ /* 860 */ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ /* 870 */ 66, 67, 68, 46, 47, 48, 49, 50, 51, 52,
+ /* 880 */ 80, 80, 55, 56, 57, 58, 59, 60, 61, 62,
+ /* 890 */ 63, 64, 65, 66, 67, 68, 4, 47, 48, 49,
+ /* 900 */ 50, 51, 52, 87, 88, 55, 56, 57, 58, 59,
+ /* 910 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 4,
+ /* 920 */ 80, 4, 42, 138, 44, 109, 156, 84, 36, 114,
+ /* 930 */ 87, 88, 156, 4, 80, 161, 166, 84, 125, 47,
+ /* 940 */ 87, 88, 166, 161, 156, 85, 4, 171, 172, 101,
+ /* 950 */ 102, 103, 109, 157, 166, 63, 64, 65, 78, 101,
+ /* 960 */ 102, 103, 79, 71, 80, 191, 192, 122, 173, 174,
+ /* 970 */ 175, 79, 80, 191, 192, 180, 84, 4, 82, 87,
+ /* 980 */ 88, 80, 65, 91, 92, 93, 85, 82, 214, 215,
+ /* 990 */ 4, 217, 218, 65, 4, 142, 214, 215, 210, 217,
+ /* 1000 */ 218, 109, 87, 88, 87, 88, 230, 231, 79, 36,
+ /* 1010 */ 236, 237, 80, 84, 4, 80, 87, 88, 100, 237,
+ /* 1020 */ 47, 141, 130, 108, 228, 133, 109, 135, 136, 87,
+ /* 1030 */ 88, 167, 4, 0, 80, 156, 63, 64, 109, 121,
+ /* 1040 */ 161, 112, 176, 4, 71, 166, 4, 130, 4, 156,
+ /* 1050 */ 32, 79, 79, 80, 79, 22, 177, 84, 4, 166,
+ /* 1060 */ 87, 88, 156, 80, 91, 92, 93, 203, 85, 32,
+ /* 1070 */ 84, 192, 166, 87, 88, 4, 156, 87, 88, 137,
+ /* 1080 */ 187, 156, 109, 158, 4, 79, 166, 167, 222, 4,
+ /* 1090 */ 36, 166, 156, 187, 84, 109, 79, 87, 88, 4,
+ /* 1100 */ 221, 47, 166, 130, 156, 72, 133, 79, 135, 136,
+ /* 1110 */ 98, 4, 84, 85, 166, 87, 88, 63, 64, 109,
+ /* 1120 */ 130, 4, 229, 84, 4, 71, 87, 88, 84, 87,
+ /* 1130 */ 88, 87, 88, 79, 80, 229, 4, 109, 84, 4,
+ /* 1140 */ 112, 87, 88, 36, 4, 91, 92, 93, 109, 167,
+ /* 1150 */ 122, 123, 80, 109, 47, 84, 4, 85, 87, 88,
+ /* 1160 */ 81, 31, 106, 109, 122, 156, 100, 87, 88, 10,
+ /* 1170 */ 63, 64, 87, 88, 167, 166, 80, 47, 71, 84,
+ /* 1180 */ 120, 85, 87, 88, 130, 203, 79, 133, 80, 135,
+ /* 1190 */ 136, 84, 4, 85, 87, 88, 111, 105, 91, 92,
+ /* 1200 */ 93, 84, 122, 4, 87, 88, 4, 87, 88, 48,
+ /* 1210 */ 203, 4, 48, 131, 143, 156, 109, 79, 20, 87,
+ /* 1220 */ 88, 156, 87, 88, 36, 166, 80, 87, 88, 4,
+ /* 1230 */ 100, 166, 72, 81, 72, 47, 106, 130, 33, 87,
+ /* 1240 */ 133, 146, 135, 136, 109, 138, 187, 33, 4, 109,
+ /* 1250 */ 4, 63, 64, 170, 171, 172, 156, 4, 158, 71,
+ /* 1260 */ 85, 144, 130, 141, 4, 145, 166, 79, 156, 204,
+ /* 1270 */ 205, 119, 84, 212, 79, 87, 88, 4, 166, 91,
+ /* 1280 */ 92, 93, 36, 222, 4, 100, 87, 88, 229, 87,
+ /* 1290 */ 88, 4, 109, 47, 87, 88, 120, 109, 121, 17,
+ /* 1300 */ 4, 144, 4, 87, 80, 117, 80, 165, 109, 63,
+ /* 1310 */ 64, 109, 87, 88, 231, 222, 36, 71, 130, 81,
+ /* 1320 */ 206, 133, 210, 135, 136, 79, 80, 47, 63, 64,
+ /* 1330 */ 84, 87, 88, 87, 88, 156, 156, 91, 92, 93,
+ /* 1340 */ 87, 88, 179, 63, 64, 166, 166, 87, 88, 142,
+ /* 1350 */ 179, 71, 156, 109, 158, 109, 91, 92, 154, 79,
+ /* 1360 */ 87, 88, 166, 155, 84, 112, 187, 87, 88, 100,
+ /* 1370 */ 73, 91, 92, 93, 87, 88, 130, 156, 156, 133,
+ /* 1380 */ 158, 135, 136, 87, 88, 87, 88, 166, 166, 109,
+ /* 1390 */ 170, 171, 172, 170, 171, 172, 154, 156, 170, 171,
+ /* 1400 */ 172, 156, 154, 143, 170, 171, 172, 166, 229, 154,
+ /* 1410 */ 130, 166, 160, 133, 156, 135, 136, 130, 177, 146,
+ /* 1420 */ 85, 155, 177, 156, 166, 158, 130, 156, 130, 155,
+ /* 1430 */ 183, 28, 156, 166, 156, 177, 155, 166, 117, 156,
+ /* 1440 */ 155, 192, 166, 129, 166, 212, 156, 156, 177, 166,
+ /* 1450 */ 199, 231, 198, 177, 231, 177, 166, 166, 197, 231,
+ /* 1460 */ 177, 127, 221, 200, 126, 231, 221, 177, 177, 124,
+ /* 1470 */ 128, 201, 99, 156, 156, 156, 68, 47, 222, 221,
+ /* 1480 */ 156, 156, 225, 166, 166, 166, 138, 82, 156, 166,
+ /* 1490 */ 166, 166, 221, 156, 177, 177, 177, 221, 166, 221,
+ /* 1500 */ 156, 177, 177, 166, 221, 156, 156, 4, 156, 177,
+ /* 1510 */ 166, 221, 221, 156, 156, 166, 166, 209, 166, 209,
+ /* 1520 */ 82, 177, 156, 166, 166, 155, 177, 177, 166, 177,
+ /* 1530 */ 79, 156, 166, 178, 177, 177, 183, 155, 221, 221,
+ /* 1540 */ 221, 166, 155, 177, 155, 221, 221, 156, 156, 156,
+ /* 1550 */ 156, 156, 177, 221, 156, 178, 156, 166, 166, 166,
+ /* 1560 */ 166, 166, 155, 209, 166, 221, 166, 82, 177, 177,
+ /* 1570 */ 221, 221, 177, 221, 156, 177, 156, 177, 221, 221,
+ /* 1580 */ 156, 156, 158, 156, 166, 209, 166, 221, 82, 24,
+ /* 1590 */ 166, 166, 82, 166, 234, 177, 221, 177, 235, 156,
+ /* 1600 */ 138, 158, 177, 197, 177, 156, 190, 45, 156, 166,
+ /* 1610 */ 156, 82, 221, 221, 156, 166, 221, 156, 166, 221,
+ /* 1620 */ 166, 221, 156, 156, 166, 156, 82, 166, 219, 79,
+ /* 1630 */ 156, 190, 166, 166, 82, 166, 82, 156, 209, 221,
+ /* 1640 */ 166, 221, 156, 155, 209, 156, 221, 166, 221, 156,
+ /* 1650 */ 156, 156, 166, 82, 82, 166, 15, 238, 190, 166,
+ /* 1660 */ 166, 166, 239, 121, 238, 194, 176, 231, 196, 185,
+ /* 1670 */ 231, 226, 176, 208, 176, 197, 167, 233, 181, 209,
+ /* 1680 */ 167, 167, 182, 182, 182, 167, 223, 232, 240, 207,
+ /* 1690 */ 240, 227, 193, 189, 186, 240, 189,
+};
+#define YY_SHIFT_USE_DFLT (-101)
+#define YY_SHIFT_COUNT (343)
+#define YY_SHIFT_MIN (-100)
+#define YY_SHIFT_MAX (1641)
+static const short yy_shift_ofst[] = {
+ /* 0 */ 273, -7, 499, -4, 141, 892, 1246, 1188, 533, 533,
+ /* 10 */ 13, 577, 567, 1107, 1280, 725, 81, 366, 1054, 973,
+ /* 20 */ 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280,
+ /* 30 */ 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280,
+ /* 40 */ 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1028, 43,
+ /* 50 */ 1296, 1296, 1296, 1296, 1265, 1265, 1296, 1265, 1265, 1265,
+ /* 60 */ 524, 173, 929, 1117, 1095, 1071, 1044, 1039, 1010, 986,
+ /* 70 */ 251, 1287, 1287, 1298, 1130, 1296, 1287, 255, 301, 153,
+ /* 80 */ 917, 853, 843, 540, 202, 531, 1273, 1260, 1253, 1244,
+ /* 90 */ 1207, 1202, 1132, 1199, 1140, 1135, 1120, 1085, 731, 816,
+ /* 100 */ 915, 728, 1080, 1042, 1152, 1152, 611, 1152, 990, 625,
+ /* 110 */ 942, 195, 605, 1225, 1225, 1225, 1225, 1225, 1225, 1225,
+ /* 120 */ 1225, -30, 1033, 167, 1321, 1321, -101, 502, 502, 502,
+ /* 130 */ 502, 502, 502, 502, 527, 327, 659, 778, 742, 716,
+ /* 140 */ 692, 359, 804, 804, 827, 850, 850, 405, 405, 405,
+ /* 150 */ 405, 204, 211, 1, 233, 1, 181, 522, 35, 375,
+ /* 160 */ -20, 121, -76, -100, -100, 858, 426, -100, -100, 166,
+ /* 170 */ 690, 690, 690, 200, 200, 200, 566, 162, 1108, 164,
+ /* 180 */ 93, 918, 164, 550, 678, 678, 565, 41, 164, 1641,
+ /* 190 */ 1542, 1641, 1552, 1562, 1572, 1571, 1554, 1269, 1552, 1562,
+ /* 200 */ 1550, 1544, 1529, 1562, 1314, 1510, 1462, 1565, 1506, 1485,
+ /* 210 */ 1451, 1269, 1269, 1269, 1269, 1403, 1503, 1451, 1269, 1438,
+ /* 220 */ 1503, 1405, 1348, 1430, 1408, 1373, 1342, 1345, 1334, 1338,
+ /* 230 */ 1314, 1321, 1269, 1269, 1403, 1269, 1269, 1335, 1297, 1297,
+ /* 240 */ 1297, 1269, 1297, -101, -101, -101, -101, -101, -101, -101,
+ /* 250 */ -101, 458, 15, 880, 349, 848, 564, 1096, 706, 1072,
+ /* 260 */ 983, 901, 590, 582, 451, 241, 449, 86, 38, -11,
+ /* 270 */ 55, 28, -59, 1238, 1157, 1226, 1224, 1216, 1282, 1177,
+ /* 280 */ 1176, 1183, 1185, 1195, 1122, 1214, 1175, 1205, 1198, 1162,
+ /* 290 */ 1160, 1146, 1138, 1082, 1164, 1161, 1092, 1060, 1159, 1066,
+ /* 300 */ 1079, 1056, 1012, 1017, 1037, 1006, 975, 972, 1018, 954,
+ /* 310 */ 935, 932, 928, 905, 896, 845, 884, 883, 860, 813,
+ /* 320 */ 860, 854, 815, 785, 840, 801, 800, 736, 617, 636,
+ /* 330 */ 588, 559, 555, 532, 316, 498, 418, 407, 317, 178,
+ /* 340 */ 143, 87, 130, -41,
+};
+#define YY_REDUCE_USE_DFLT (-194)
+#define YY_REDUCE_COUNT (250)
+#define YY_REDUCE_MIN (-193)
+#define YY_REDUCE_MAX (1518)
+static const short yy_reduce_ofst[] = {
+ /* 0 */ 192, -34, 774, -57, 782, 318, -148, 879, 776, 374,
+ /* 10 */ 132, 29, 320, 512, 466, 277, 1427, 1425, 1420, 1418,
+ /* 20 */ 1400, 1398, 1395, 1392, 1391, 1375, 1366, 1358, 1357, 1352,
+ /* 30 */ 1350, 1349, 1344, 1332, 1325, 1324, 1319, 1318, 1317, 1291,
+ /* 40 */ 1290, 1283, 1278, 1276, 1271, 1258, 1245, 1241, 1065, 795,
+ /* 50 */ 1179, 1059, 906, 893, 1234, 1228, -75, 1223, 1220, 1083,
+ /* 60 */ 280, 431, 286, 920, 1443, 1424, 1267, 1222, 1196, 1100,
+ /* 70 */ 925, 1112, 788, 470, 297, -131, 46, 866, 1061, 307,
+ /* 80 */ 1489, 1495, 1494, 936, 1493, 1489, 936, 936, 1486, 936,
+ /* 90 */ 936, 936, 1481, 936, 936, 936, 1474, 1469, 936, 1467,
+ /* 100 */ 1466, 1461, 1458, 1454, 1007, 982, 1452, 864, 1449, 936,
+ /* 110 */ 1394, 1393, 1337, 1221, 1180, 1009, 948, 936, 770, 215,
+ /* 120 */ -80, 796, 634, 656, 242, -45, -193, 1093, 1093, 1093,
+ /* 130 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ /* 140 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ /* 150 */ 1093, 1093, 1093, 1507, 1508, 1504, 1499, 1482, 1499, 1464,
+ /* 160 */ 1463, 1093, 1499, 1499, 1499, 1444, 1455, 1499, 1499, 1518,
+ /* 170 */ 1502, 1501, 1500, 1514, 1513, 1509, 1470, 1478, 1484, 1498,
+ /* 180 */ 1497, 1465, 1496, 1445, 1439, 1436, 1472, 1471, 1490, 1426,
+ /* 190 */ 1423, 1419, 1435, 1468, 1354, 1354, 1354, 1488, 1429, 1441,
+ /* 200 */ 1409, 1354, 1354, 1416, 1406, 1354, 1363, 1360, 1376, 1354,
+ /* 210 */ 1377, 1407, 1389, 1387, 1382, 1353, 1362, 1355, 1370, 1310,
+ /* 220 */ 1323, 1308, 1257, 1256, 1093, 1233, 1270, 1263, 1251, 1254,
+ /* 230 */ 1261, 1249, 1285, 1281, 1247, 1274, 1266, 1252, 1255, 1248,
+ /* 240 */ 1242, 1208, 1204, 1171, 1163, 1114, 1093, 1093, 1093, 1093,
+ /* 250 */ 1142,
+};
+static const YYACTIONTYPE yy_default[] = {
+ /* 0 */ 589, 936, 936, 862, 903, 851, 851, 851, 936, 936,
+ /* 10 */ 730, 936, 851, 851, 851, 936, 851, 851, 851, 851,
+ /* 20 */ 851, 851, 851, 851, 851, 851, 851, 851, 851, 851,
+ /* 30 */ 851, 851, 851, 851, 851, 851, 851, 851, 851, 851,
+ /* 40 */ 851, 851, 851, 851, 851, 851, 851, 851, 724, 608,
+ /* 50 */ 936, 936, 936, 936, 936, 936, 936, 936, 936, 936,
+ /* 60 */ 616, 720, 730, 936, 936, 936, 936, 790, 777, 768,
+ /* 70 */ 936, 800, 800, 783, 679, 936, 800, 756, 752, 936,
+ /* 80 */ 839, 936, 936, 731, 936, 839, 936, 936, 936, 936,
+ /* 90 */ 936, 791, 784, 778, 769, 936, 936, 936, 936, 936,
+ /* 100 */ 936, 936, 936, 936, 720, 720, 936, 720, 936, 936,
+ /* 110 */ 936, 840, 594, 936, 882, 936, 936, 936, 936, 936,
+ /* 120 */ 936, 605, 589, 936, 936, 936, 710, 736, 773, 761,
+ /* 130 */ 863, 856, 857, 855, 852, 852, 852, 852, 852, 852,
+ /* 140 */ 852, 852, 852, 823, 816, 827, 815, 831, 841, 826,
+ /* 150 */ 818, 817, 819, 936, 936, 936, 936, 723, 936, 936,
+ /* 160 */ 936, 820, 936, 789, 698, 936, 910, 693, 601, 618,
+ /* 170 */ 936, 936, 936, 936, 936, 936, 936, 772, 670, 756,
+ /* 180 */ 645, 738, 756, 858, 936, 936, 721, 708, 756, 934,
+ /* 190 */ 931, 934, 739, 683, 739, 739, 739, 681, 739, 683,
+ /* 200 */ 796, 739, 739, 683, 772, 739, 918, 915, 739, 739,
+ /* 210 */ 871, 681, 681, 681, 681, 662, 936, 871, 681, 739,
+ /* 220 */ 936, 739, 936, 852, 821, 752, 762, 748, 760, 757,
+ /* 230 */ 772, 936, 681, 681, 662, 681, 681, 665, 593, 593,
+ /* 240 */ 593, 681, 593, 649, 649, 726, 830, 829, 828, 822,
+ /* 250 */ 629, 864, 936, 936, 936, 936, 936, 936, 936, 936,
+ /* 260 */ 936, 936, 936, 936, 936, 936, 936, 936, 936, 763,
+ /* 270 */ 936, 936, 936, 936, 936, 936, 936, 936, 936, 881,
+ /* 280 */ 936, 936, 936, 936, 936, 936, 914, 913, 936, 936,
+ /* 290 */ 936, 936, 936, 936, 936, 936, 936, 936, 902, 936,
+ /* 300 */ 936, 936, 936, 936, 936, 936, 936, 936, 936, 936,
+ /* 310 */ 936, 936, 936, 936, 936, 936, 936, 936, 758, 936,
+ /* 320 */ 861, 843, 701, 850, 936, 936, 936, 936, 936, 842,
+ /* 330 */ 853, 810, 936, 749, 936, 809, 806, 808, 611, 936,
+ /* 340 */ 936, 936, 936, 936, 586, 590, 935, 933, 932, 930,
+ /* 350 */ 890, 889, 888, 886, 895, 894, 893, 892, 891, 887,
+ /* 360 */ 885, 884, 883, 880, 787, 775, 766, 697, 929, 927,
+ /* 370 */ 928, 879, 877, 878, 696, 695, 692, 691, 690, 869,
+ /* 380 */ 868, 866, 865, 867, 604, 906, 909, 908, 907, 912,
+ /* 390 */ 911, 904, 917, 916, 921, 925, 924, 923, 922, 920,
+ /* 400 */ 901, 795, 794, 792, 797, 788, 793, 780, 786, 785,
+ /* 410 */ 776, 779, 684, 771, 767, 770, 905, 694, 603, 741,
+ /* 420 */ 602, 607, 668, 669, 677, 680, 675, 678, 674, 673,
+ /* 430 */ 672, 676, 671, 667, 610, 609, 623, 621, 622, 620,
+ /* 440 */ 619, 617, 639, 638, 635, 637, 634, 636, 633, 632,
+ /* 450 */ 631, 630, 628, 661, 647, 646, 874, 876, 875, 873,
+ /* 460 */ 872, 654, 653, 659, 658, 657, 656, 652, 655, 651,
+ /* 470 */ 650, 648, 644, 814, 813, 807, 835, 707, 706, 715,
+ /* 480 */ 713, 712, 711, 747, 746, 745, 744, 743, 742, 735,
+ /* 490 */ 733, 729, 728, 734, 732, 727, 719, 717, 718, 716,
+ /* 500 */ 612, 802, 799, 801, 798, 737, 725, 722, 709, 751,
+ /* 510 */ 753, 854, 844, 834, 845, 740, 832, 833, 704, 703,
+ /* 520 */ 702, 853, 850, 846, 926, 838, 849, 837, 836, 825,
+ /* 530 */ 824, 812, 847, 848, 811, 750, 765, 898, 897, 900,
+ /* 540 */ 899, 896, 764, 625, 624, 705, 700, 699, 805, 804,
+ /* 550 */ 803, 643, 755, 754, 642, 664, 663, 660, 641, 640,
+ /* 560 */ 627, 626, 606, 600, 599, 598, 597, 615, 614, 613,
+ /* 570 */ 611, 596, 595, 689, 688, 687, 686, 685, 682, 592,
+ /* 580 */ 591, 588, 587, 585,
+};
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+ 0, /* $ => nothing */
+ 0, /* ILLEGAL => nothing */
+ 0, /* COMMENT => nothing */
+ 0, /* SPACE => nothing */
+ 0, /* ID => nothing */
+ 4, /* ABORT => ID */
+ 4, /* AFTER => ID */
+ 4, /* ASC => ID */
+ 4, /* ATTACH => ID */
+ 4, /* BEFORE => ID */
+ 4, /* BEGIN => ID */
+ 4, /* CASCADE => ID */
+ 4, /* CLUSTER => ID */
+ 4, /* CONFLICT => ID */
+ 4, /* COPY => ID */
+ 4, /* DATABASE => ID */
+ 4, /* DEFERRED => ID */
+ 4, /* DELIMITERS => ID */
+ 4, /* DESC => ID */
+ 4, /* DETACH => ID */
+ 4, /* EACH => ID */
+ 4, /* END => ID */
+ 4, /* EXPLAIN => ID */
+ 4, /* FAIL => ID */
+ 4, /* FOR => ID */
+ 4, /* GLOB => ID */
+ 4, /* IGNORE => ID */
+ 4, /* IMMEDIATE => ID */
+ 4, /* INITIALLY => ID */
+ 4, /* INSTEAD => ID */
+ 4, /* LIKE => ID */
+ 4, /* MATCH => ID */
+ 4, /* KEY => ID */
+ 4, /* OF => ID */
+ 4, /* OFFSET => ID */
+ 4, /* PRAGMA => ID */
+ 4, /* RAISE => ID */
+ 4, /* REPLACE => ID */
+ 4, /* RESTRICT => ID */
+ 4, /* ROW => ID */
+ 4, /* STATEMENT => ID */
+ 4, /* TEMP => ID */
+ 4, /* TRIGGER => ID */
+ 4, /* VACUUM => ID */
+ 4, /* VIEW => ID */
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ YYACTIONTYPE stateno; /* The state-number */
+ YYCODETYPE major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+ QList<Token*>* tokens = nullptr;
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+ int yyidxMax; /* Maximum value of yyidx */
+#endif
+ int yyerrcnt; /* Shifts left before out of the error */
+ sqlite2_parseARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+void *sqlite2_parseCopyParserState(void* other)
+{
+ yyParser *pParser;
+ yyParser *otherParser = (yyParser*)other;
+
+ // Copy parser
+ pParser = (yyParser*)malloc((size_t)sizeof(yyParser));
+ memcpy(pParser, other, (size_t)sizeof(yyParser));
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = malloc((size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)other)->yystack, (size_t)stackSize);
+#endif
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(otherParser->yystack[i].tokens);
+ }
+
+ return pParser;
+}
+
+void sqlite2_parseAddToken(void* other, Token* token)
+{
+ yyParser *otherParser = (yyParser*)other;
+ if (otherParser->yyidx < 0)
+ return; // Nothing on stack yet. Might happen when parsing just whitespaces, nothing else.
+
+ otherParser->yystack[otherParser->yyidx].tokens->append(token);
+}
+
+void sqlite2_parseRestoreParserState(void* saved, void* target)
+{
+ yyParser *pParser = (yyParser*)target;
+ yyParser *savedParser = (yyParser*)saved;
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+ memcpy(pParser, saved, (size_t)sizeof(yyParser));
+
+ for (int i = 0; i <= savedParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(savedParser->yystack[i].tokens);
+ }
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = relloc(pParser->yystack, (size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)saved)->yystack, (size_t)stackSize);
+#endif
+}
+
+void sqlite2_parseFreeSavedState(void* other)
+{
+ yyParser *pParser = (yyParser*)other;
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ free(other);
+}
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void sqlite2_parseTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *const yyTokenName[] = {
+ "$", "ILLEGAL", "COMMENT", "SPACE",
+ "ID", "ABORT", "AFTER", "ASC",
+ "ATTACH", "BEFORE", "BEGIN", "CASCADE",
+ "CLUSTER", "CONFLICT", "COPY", "DATABASE",
+ "DEFERRED", "DELIMITERS", "DESC", "DETACH",
+ "EACH", "END", "EXPLAIN", "FAIL",
+ "FOR", "GLOB", "IGNORE", "IMMEDIATE",
+ "INITIALLY", "INSTEAD", "LIKE", "MATCH",
+ "KEY", "OF", "OFFSET", "PRAGMA",
+ "RAISE", "REPLACE", "RESTRICT", "ROW",
+ "STATEMENT", "TEMP", "TRIGGER", "VACUUM",
+ "VIEW", "OR", "AND", "NOT",
+ "EQ", "NE", "ISNULL", "NOTNULL",
+ "IS", "BETWEEN", "IN", "GT",
+ "GE", "LT", "LE", "BITAND",
+ "BITOR", "LSHIFT", "RSHIFT", "PLUS",
+ "MINUS", "STAR", "SLASH", "REM",
+ "CONCAT", "UMINUS", "UPLUS", "BITNOT",
+ "SEMI", "TRANSACTION", "ID_TRANS", "COMMIT",
+ "ROLLBACK", "CREATE", "TABLE", "LP",
+ "RP", "AS", "DOT", "ID_TAB_NEW",
+ "ID_DB", "COMMA", "ID_COL_NEW", "STRING",
+ "JOIN_KW", "ID_COL_TYPE", "DEFAULT", "INTEGER",
+ "FLOAT", "NULL", "CONSTRAINT", "PRIMARY",
+ "UNIQUE", "CHECK", "REFERENCES", "COLLATE",
+ "ON", "INSERT", "DELETE", "UPDATE",
+ "ID_FK_MATCH", "SET", "DEFERRABLE", "FOREIGN",
+ "ID_CONSTR", "ID_TAB", "DROP", "ID_VIEW_NEW",
+ "ID_VIEW", "UNION", "ALL", "EXCEPT",
+ "INTERSECT", "SELECT", "DISTINCT", "ID_ALIAS",
+ "FROM", "USING", "JOIN", "ID_JOIN_OPTS",
+ "ORDER", "BY", "GROUP", "HAVING",
+ "LIMIT", "WHERE", "ID_COL", "INTO",
+ "VALUES", "VARIABLE", "LIKE_KW", "CASE",
+ "ID_FN", "ID_ERR_MSG", "WHEN", "THEN",
+ "ELSE", "INDEX", "ID_IDX_NEW", "ID_IDX",
+ "ID_PRAGMA", "ID_TRIG_NEW", "ID_TRIG", "error",
+ "cmd", "input", "cmdlist", "ecmd",
+ "explain", "cmdx", "trans_opt", "onconf",
+ "nm", "temp", "fullname", "columnlist",
+ "conslist_opt", "select", "column", "columnid",
+ "type", "carglist", "id", "ids",
+ "typetoken", "typename", "signed", "plus_num",
+ "minus_num", "ccons", "ccons_nm", "carg",
+ "sortorder", "expr", "idxlist_opt", "refargs",
+ "defer_subclause", "refarg", "refact", "init_deferred_pred_opt",
+ "conslist", "tconscomma", "tcons", "idxlist",
+ "defer_subclause_opt", "resolvetype", "orconf", "select_stmt",
+ "oneselect", "multiselect_op", "distinct", "selcollist",
+ "from", "where_opt", "groupby_opt", "having_opt",
+ "orderby_opt", "limit_opt", "sclp", "as",
+ "joinsrc", "singlesrc", "seltablist", "joinop",
+ "joinconstr_opt", "dbnm", "inscollist", "sortlist",
+ "collate", "nexprlist", "delete_stmt", "update_stmt",
+ "setlist", "insert_stmt", "insert_cmd", "inscollist_opt",
+ "exprlist", "exprx", "not_opt", "likeop",
+ "case_operand", "case_exprlist", "case_else", "raisetype",
+ "uniqueflag", "idxlist_single", "nmnum", "number",
+ "trigger_time", "trigger_event", "foreach_clause", "when_clause",
+ "trigger_cmd_list", "trigger_cmd", "database_kw_opt", "key_opt",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+ /* 0 */ "input ::= cmdlist",
+ /* 1 */ "cmdlist ::= cmdlist ecmd",
+ /* 2 */ "cmdlist ::= ecmd",
+ /* 3 */ "ecmd ::= SEMI",
+ /* 4 */ "ecmd ::= explain cmdx SEMI",
+ /* 5 */ "explain ::=",
+ /* 6 */ "explain ::= EXPLAIN",
+ /* 7 */ "cmdx ::= cmd",
+ /* 8 */ "cmd ::= BEGIN trans_opt onconf",
+ /* 9 */ "trans_opt ::=",
+ /* 10 */ "trans_opt ::= TRANSACTION",
+ /* 11 */ "trans_opt ::= TRANSACTION nm",
+ /* 12 */ "trans_opt ::= TRANSACTION ID_TRANS",
+ /* 13 */ "cmd ::= COMMIT trans_opt",
+ /* 14 */ "cmd ::= END trans_opt",
+ /* 15 */ "cmd ::= ROLLBACK trans_opt",
+ /* 16 */ "cmd ::= CREATE temp TABLE fullname LP columnlist conslist_opt RP",
+ /* 17 */ "cmd ::= CREATE temp TABLE fullname AS select",
+ /* 18 */ "cmd ::= CREATE temp TABLE nm DOT ID_TAB_NEW",
+ /* 19 */ "cmd ::= CREATE temp TABLE ID_DB|ID_TAB_NEW",
+ /* 20 */ "temp ::= TEMP",
+ /* 21 */ "temp ::=",
+ /* 22 */ "columnlist ::= columnlist COMMA column",
+ /* 23 */ "columnlist ::= column",
+ /* 24 */ "column ::= columnid type carglist",
+ /* 25 */ "columnid ::= nm",
+ /* 26 */ "columnid ::= ID_COL_NEW",
+ /* 27 */ "id ::= ID",
+ /* 28 */ "ids ::= ID|STRING",
+ /* 29 */ "nm ::= id",
+ /* 30 */ "nm ::= STRING",
+ /* 31 */ "nm ::= JOIN_KW",
+ /* 32 */ "type ::=",
+ /* 33 */ "type ::= typetoken",
+ /* 34 */ "typetoken ::= typename",
+ /* 35 */ "typetoken ::= typename LP signed RP",
+ /* 36 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 37 */ "typename ::= ids",
+ /* 38 */ "typename ::= typename ids",
+ /* 39 */ "typename ::= ID_COL_TYPE",
+ /* 40 */ "signed ::= plus_num",
+ /* 41 */ "signed ::= minus_num",
+ /* 42 */ "carglist ::= carglist ccons",
+ /* 43 */ "carglist ::= carglist ccons_nm ccons",
+ /* 44 */ "carglist ::= carglist carg",
+ /* 45 */ "carglist ::=",
+ /* 46 */ "carg ::= DEFAULT STRING",
+ /* 47 */ "carg ::= DEFAULT ID",
+ /* 48 */ "carg ::= DEFAULT INTEGER",
+ /* 49 */ "carg ::= DEFAULT PLUS INTEGER",
+ /* 50 */ "carg ::= DEFAULT MINUS INTEGER",
+ /* 51 */ "carg ::= DEFAULT FLOAT",
+ /* 52 */ "carg ::= DEFAULT PLUS FLOAT",
+ /* 53 */ "carg ::= DEFAULT MINUS FLOAT",
+ /* 54 */ "carg ::= DEFAULT NULL",
+ /* 55 */ "ccons_nm ::= CONSTRAINT nm",
+ /* 56 */ "ccons ::= NULL onconf",
+ /* 57 */ "ccons ::= NOT NULL onconf",
+ /* 58 */ "ccons ::= PRIMARY KEY sortorder onconf",
+ /* 59 */ "ccons ::= UNIQUE onconf",
+ /* 60 */ "ccons ::= CHECK LP expr RP onconf",
+ /* 61 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /* 62 */ "ccons ::= defer_subclause",
+ /* 63 */ "ccons ::= COLLATE id",
+ /* 64 */ "ccons ::= CHECK LP RP",
+ /* 65 */ "refargs ::=",
+ /* 66 */ "refargs ::= refargs refarg",
+ /* 67 */ "refarg ::= MATCH nm",
+ /* 68 */ "refarg ::= ON INSERT refact",
+ /* 69 */ "refarg ::= ON DELETE refact",
+ /* 70 */ "refarg ::= ON UPDATE refact",
+ /* 71 */ "refarg ::= MATCH ID_FK_MATCH",
+ /* 72 */ "refact ::= SET NULL",
+ /* 73 */ "refact ::= SET DEFAULT",
+ /* 74 */ "refact ::= CASCADE",
+ /* 75 */ "refact ::= RESTRICT",
+ /* 76 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 77 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 78 */ "init_deferred_pred_opt ::=",
+ /* 79 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 80 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 81 */ "conslist_opt ::=",
+ /* 82 */ "conslist_opt ::= COMMA conslist",
+ /* 83 */ "conslist ::= conslist tconscomma tcons",
+ /* 84 */ "conslist ::= tcons",
+ /* 85 */ "tconscomma ::= COMMA",
+ /* 86 */ "tconscomma ::=",
+ /* 87 */ "tcons ::= CONSTRAINT nm",
+ /* 88 */ "tcons ::= PRIMARY KEY LP idxlist RP onconf",
+ /* 89 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+ /* 90 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 91 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+ /* 92 */ "tcons ::= CONSTRAINT ID_CONSTR",
+ /* 93 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB",
+ /* 94 */ "tcons ::= CHECK LP RP onconf",
+ /* 95 */ "defer_subclause_opt ::=",
+ /* 96 */ "defer_subclause_opt ::= defer_subclause",
+ /* 97 */ "onconf ::=",
+ /* 98 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 99 */ "orconf ::=",
+ /* 100 */ "orconf ::= OR resolvetype",
+ /* 101 */ "resolvetype ::= ROLLBACK",
+ /* 102 */ "resolvetype ::= ABORT",
+ /* 103 */ "resolvetype ::= FAIL",
+ /* 104 */ "resolvetype ::= IGNORE",
+ /* 105 */ "resolvetype ::= REPLACE",
+ /* 106 */ "cmd ::= DROP TABLE fullname",
+ /* 107 */ "cmd ::= DROP TABLE nm DOT ID_TAB",
+ /* 108 */ "cmd ::= DROP TABLE ID_DB|ID_TAB",
+ /* 109 */ "cmd ::= CREATE temp VIEW nm AS select",
+ /* 110 */ "cmd ::= CREATE temp VIEW ID_VIEW_NEW",
+ /* 111 */ "cmd ::= DROP VIEW nm",
+ /* 112 */ "cmd ::= DROP VIEW ID_VIEW",
+ /* 113 */ "cmd ::= select_stmt",
+ /* 114 */ "select_stmt ::= select",
+ /* 115 */ "select ::= oneselect",
+ /* 116 */ "select ::= select multiselect_op oneselect",
+ /* 117 */ "multiselect_op ::= UNION",
+ /* 118 */ "multiselect_op ::= UNION ALL",
+ /* 119 */ "multiselect_op ::= EXCEPT",
+ /* 120 */ "multiselect_op ::= INTERSECT",
+ /* 121 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 122 */ "distinct ::= DISTINCT",
+ /* 123 */ "distinct ::= ALL",
+ /* 124 */ "distinct ::=",
+ /* 125 */ "sclp ::= selcollist COMMA",
+ /* 126 */ "sclp ::=",
+ /* 127 */ "selcollist ::= sclp expr as",
+ /* 128 */ "selcollist ::= sclp STAR",
+ /* 129 */ "selcollist ::= sclp nm DOT STAR",
+ /* 130 */ "selcollist ::= sclp",
+ /* 131 */ "selcollist ::= sclp ID_TAB DOT STAR",
+ /* 132 */ "as ::= AS nm",
+ /* 133 */ "as ::= ids",
+ /* 134 */ "as ::= AS ID_ALIAS",
+ /* 135 */ "as ::= ID_ALIAS",
+ /* 136 */ "as ::=",
+ /* 137 */ "from ::=",
+ /* 138 */ "from ::= FROM joinsrc",
+ /* 139 */ "joinsrc ::= singlesrc seltablist",
+ /* 140 */ "joinsrc ::=",
+ /* 141 */ "seltablist ::= seltablist joinop singlesrc joinconstr_opt",
+ /* 142 */ "seltablist ::=",
+ /* 143 */ "singlesrc ::= nm dbnm as",
+ /* 144 */ "singlesrc ::= LP select RP as",
+ /* 145 */ "singlesrc ::= LP joinsrc RP as",
+ /* 146 */ "singlesrc ::=",
+ /* 147 */ "singlesrc ::= nm DOT",
+ /* 148 */ "singlesrc ::= nm DOT ID_TAB",
+ /* 149 */ "singlesrc ::= ID_DB|ID_TAB",
+ /* 150 */ "singlesrc ::= nm DOT ID_VIEW",
+ /* 151 */ "singlesrc ::= ID_DB|ID_VIEW",
+ /* 152 */ "joinconstr_opt ::= ON expr",
+ /* 153 */ "joinconstr_opt ::= USING LP inscollist RP",
+ /* 154 */ "joinconstr_opt ::=",
+ /* 155 */ "dbnm ::=",
+ /* 156 */ "dbnm ::= DOT nm",
+ /* 157 */ "fullname ::= nm dbnm",
+ /* 158 */ "joinop ::= COMMA",
+ /* 159 */ "joinop ::= JOIN",
+ /* 160 */ "joinop ::= JOIN_KW JOIN",
+ /* 161 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 162 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 163 */ "joinop ::= ID_JOIN_OPTS",
+ /* 164 */ "orderby_opt ::=",
+ /* 165 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 166 */ "sortlist ::= sortlist COMMA collate expr sortorder",
+ /* 167 */ "sortlist ::= expr collate sortorder",
+ /* 168 */ "collate ::=",
+ /* 169 */ "collate ::= COLLATE id",
+ /* 170 */ "sortorder ::= ASC",
+ /* 171 */ "sortorder ::= DESC",
+ /* 172 */ "sortorder ::=",
+ /* 173 */ "groupby_opt ::=",
+ /* 174 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 175 */ "groupby_opt ::= GROUP BY",
+ /* 176 */ "having_opt ::=",
+ /* 177 */ "having_opt ::= HAVING expr",
+ /* 178 */ "limit_opt ::=",
+ /* 179 */ "limit_opt ::= LIMIT signed",
+ /* 180 */ "limit_opt ::= LIMIT signed OFFSET signed",
+ /* 181 */ "limit_opt ::= LIMIT signed COMMA signed",
+ /* 182 */ "cmd ::= delete_stmt",
+ /* 183 */ "delete_stmt ::= DELETE FROM fullname where_opt",
+ /* 184 */ "delete_stmt ::= DELETE FROM",
+ /* 185 */ "delete_stmt ::= DELETE FROM nm DOT",
+ /* 186 */ "delete_stmt ::= DELETE FROM nm DOT ID_TAB",
+ /* 187 */ "delete_stmt ::= DELETE FROM ID_DB|ID_TAB",
+ /* 188 */ "where_opt ::=",
+ /* 189 */ "where_opt ::= WHERE expr",
+ /* 190 */ "where_opt ::= WHERE",
+ /* 191 */ "cmd ::= update_stmt",
+ /* 192 */ "update_stmt ::= UPDATE orconf fullname SET setlist where_opt",
+ /* 193 */ "update_stmt ::= UPDATE orconf",
+ /* 194 */ "update_stmt ::= UPDATE orconf nm DOT",
+ /* 195 */ "update_stmt ::= UPDATE orconf nm DOT ID_TAB",
+ /* 196 */ "update_stmt ::= UPDATE orconf ID_DB|ID_TAB",
+ /* 197 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 198 */ "setlist ::= nm EQ expr",
+ /* 199 */ "setlist ::=",
+ /* 200 */ "setlist ::= setlist COMMA",
+ /* 201 */ "setlist ::= setlist COMMA ID_COL",
+ /* 202 */ "setlist ::= ID_COL",
+ /* 203 */ "cmd ::= insert_stmt",
+ /* 204 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP",
+ /* 205 */ "insert_stmt ::= insert_cmd INTO fullname inscollist_opt select",
+ /* 206 */ "insert_stmt ::= insert_cmd INTO",
+ /* 207 */ "insert_stmt ::= insert_cmd INTO nm DOT",
+ /* 208 */ "insert_stmt ::= insert_cmd INTO ID_DB|ID_TAB",
+ /* 209 */ "insert_stmt ::= insert_cmd INTO nm DOT ID_TAB",
+ /* 210 */ "insert_cmd ::= INSERT orconf",
+ /* 211 */ "insert_cmd ::= REPLACE",
+ /* 212 */ "inscollist_opt ::=",
+ /* 213 */ "inscollist_opt ::= LP inscollist RP",
+ /* 214 */ "inscollist ::= inscollist COMMA nm",
+ /* 215 */ "inscollist ::= nm",
+ /* 216 */ "inscollist ::=",
+ /* 217 */ "inscollist ::= inscollist COMMA ID_COL",
+ /* 218 */ "inscollist ::= ID_COL",
+ /* 219 */ "exprx ::= NULL",
+ /* 220 */ "exprx ::= INTEGER",
+ /* 221 */ "exprx ::= FLOAT",
+ /* 222 */ "exprx ::= STRING",
+ /* 223 */ "exprx ::= LP expr RP",
+ /* 224 */ "exprx ::= id",
+ /* 225 */ "exprx ::= JOIN_KW",
+ /* 226 */ "exprx ::= nm DOT nm",
+ /* 227 */ "exprx ::= nm DOT nm DOT nm",
+ /* 228 */ "exprx ::= VARIABLE",
+ /* 229 */ "exprx ::= ID LP exprlist RP",
+ /* 230 */ "exprx ::= ID LP STAR RP",
+ /* 231 */ "exprx ::= expr AND expr",
+ /* 232 */ "exprx ::= expr OR expr",
+ /* 233 */ "exprx ::= expr LT|GT|GE|LE expr",
+ /* 234 */ "exprx ::= expr EQ|NE expr",
+ /* 235 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 236 */ "exprx ::= expr PLUS|MINUS expr",
+ /* 237 */ "exprx ::= expr STAR|SLASH|REM expr",
+ /* 238 */ "exprx ::= expr CONCAT expr",
+ /* 239 */ "exprx ::= expr not_opt likeop expr",
+ /* 240 */ "exprx ::= expr ISNULL|NOTNULL",
+ /* 241 */ "exprx ::= expr NOT NULL",
+ /* 242 */ "exprx ::= expr IS not_opt expr",
+ /* 243 */ "exprx ::= NOT expr",
+ /* 244 */ "exprx ::= BITNOT expr",
+ /* 245 */ "exprx ::= MINUS expr",
+ /* 246 */ "exprx ::= PLUS expr",
+ /* 247 */ "exprx ::= expr not_opt BETWEEN expr AND expr",
+ /* 248 */ "exprx ::= expr not_opt IN LP exprlist RP",
+ /* 249 */ "exprx ::= expr not_opt IN LP select RP",
+ /* 250 */ "exprx ::= expr not_opt IN nm dbnm",
+ /* 251 */ "exprx ::= LP select RP",
+ /* 252 */ "exprx ::= CASE case_operand case_exprlist case_else END",
+ /* 253 */ "exprx ::= RAISE LP raisetype COMMA nm RP",
+ /* 254 */ "exprx ::= RAISE LP IGNORE RP",
+ /* 255 */ "exprx ::= nm DOT",
+ /* 256 */ "exprx ::= nm DOT nm DOT",
+ /* 257 */ "exprx ::= expr not_opt BETWEEN expr",
+ /* 258 */ "exprx ::= CASE case_operand case_exprlist case_else",
+ /* 259 */ "exprx ::= expr not_opt IN LP exprlist",
+ /* 260 */ "exprx ::= expr not_opt IN ID_DB",
+ /* 261 */ "exprx ::= expr not_opt IN nm DOT ID_TAB",
+ /* 262 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN",
+ /* 263 */ "exprx ::= nm DOT ID_TAB|ID_COL",
+ /* 264 */ "exprx ::= nm DOT nm DOT ID_COL",
+ /* 265 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP",
+ /* 266 */ "expr ::= exprx",
+ /* 267 */ "expr ::=",
+ /* 268 */ "not_opt ::=",
+ /* 269 */ "not_opt ::= NOT",
+ /* 270 */ "likeop ::= LIKE|GLOB",
+ /* 271 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 272 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 273 */ "case_else ::= ELSE expr",
+ /* 274 */ "case_else ::=",
+ /* 275 */ "case_operand ::= exprx",
+ /* 276 */ "case_operand ::=",
+ /* 277 */ "exprlist ::= nexprlist",
+ /* 278 */ "exprlist ::=",
+ /* 279 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 280 */ "nexprlist ::= exprx",
+ /* 281 */ "cmd ::= CREATE uniqueflag INDEX nm ON nm dbnm LP idxlist RP onconf",
+ /* 282 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON ID_TAB",
+ /* 283 */ "cmd ::= CREATE uniqueflag INDEX nm DOT ID_IDX_NEW",
+ /* 284 */ "cmd ::= CREATE uniqueflag INDEX ID_DB|ID_IDX_NEW",
+ /* 285 */ "uniqueflag ::= UNIQUE",
+ /* 286 */ "uniqueflag ::=",
+ /* 287 */ "idxlist_opt ::=",
+ /* 288 */ "idxlist_opt ::= LP idxlist RP",
+ /* 289 */ "idxlist ::= idxlist COMMA idxlist_single",
+ /* 290 */ "idxlist ::= idxlist_single",
+ /* 291 */ "idxlist_single ::= nm sortorder",
+ /* 292 */ "idxlist_single ::= ID_COL",
+ /* 293 */ "cmd ::= DROP INDEX fullname",
+ /* 294 */ "cmd ::= DROP INDEX nm DOT ID_IDX",
+ /* 295 */ "cmd ::= DROP INDEX ID_DB|ID_IDX",
+ /* 296 */ "cmd ::= COPY orconf nm dbnm FROM nm USING DELIMITERS STRING",
+ /* 297 */ "cmd ::= COPY orconf nm dbnm FROM nm",
+ /* 298 */ "cmd ::= VACUUM",
+ /* 299 */ "cmd ::= VACUUM nm",
+ /* 300 */ "cmd ::= PRAGMA ids",
+ /* 301 */ "cmd ::= PRAGMA nm EQ nmnum",
+ /* 302 */ "cmd ::= PRAGMA nm LP nmnum RP",
+ /* 303 */ "cmd ::= PRAGMA nm EQ minus_num",
+ /* 304 */ "cmd ::= PRAGMA nm LP minus_num RP",
+ /* 305 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA",
+ /* 306 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA",
+ /* 307 */ "nmnum ::= plus_num",
+ /* 308 */ "nmnum ::= nm",
+ /* 309 */ "nmnum ::= ON",
+ /* 310 */ "nmnum ::= DELETE",
+ /* 311 */ "nmnum ::= DEFAULT",
+ /* 312 */ "plus_num ::= PLUS number",
+ /* 313 */ "plus_num ::= number",
+ /* 314 */ "minus_num ::= MINUS number",
+ /* 315 */ "number ::= INTEGER",
+ /* 316 */ "number ::= FLOAT",
+ /* 317 */ "cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause BEGIN trigger_cmd_list END",
+ /* 318 */ "cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause",
+ /* 319 */ "cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause BEGIN trigger_cmd_list",
+ /* 320 */ "cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON ID_TAB|ID_DB",
+ /* 321 */ "cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm DOT ID_TAB",
+ /* 322 */ "cmd ::= CREATE temp TRIGGER ID_TRIG_NEW",
+ /* 323 */ "trigger_time ::= BEFORE",
+ /* 324 */ "trigger_time ::= AFTER",
+ /* 325 */ "trigger_time ::= INSTEAD OF",
+ /* 326 */ "trigger_time ::=",
+ /* 327 */ "trigger_event ::= DELETE",
+ /* 328 */ "trigger_event ::= INSERT",
+ /* 329 */ "trigger_event ::= UPDATE",
+ /* 330 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 331 */ "foreach_clause ::=",
+ /* 332 */ "foreach_clause ::= FOR EACH ROW",
+ /* 333 */ "foreach_clause ::= FOR EACH STATEMENT",
+ /* 334 */ "when_clause ::=",
+ /* 335 */ "when_clause ::= WHEN expr",
+ /* 336 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 337 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 338 */ "trigger_cmd ::= update_stmt",
+ /* 339 */ "trigger_cmd ::= insert_stmt",
+ /* 340 */ "trigger_cmd ::= delete_stmt",
+ /* 341 */ "trigger_cmd ::= select_stmt",
+ /* 342 */ "raisetype ::= ROLLBACK|ABORT|FAIL",
+ /* 343 */ "cmd ::= DROP TRIGGER fullname",
+ /* 344 */ "cmd ::= DROP TRIGGER nm DOT ID_TRIG",
+ /* 345 */ "cmd ::= DROP TRIGGER ID_DB|ID_TRIG",
+ /* 346 */ "cmd ::= ATTACH database_kw_opt ids AS ids key_opt",
+ /* 347 */ "key_opt ::=",
+ /* 348 */ "key_opt ::= USING ids",
+ /* 349 */ "database_kw_opt ::= DATABASE",
+ /* 350 */ "database_kw_opt ::=",
+ /* 351 */ "cmd ::= DETACH database_kw_opt nm",
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.
+*/
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
+#endif
+ }
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to sqlite2_parse and sqlite2_parseFree.
+*/
+void *sqlite2_parseAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+#ifdef YYTRACKMAXSTACKDEPTH
+ pParser->yyidxMax = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ pParser->yystack = NULL;
+ pParser->yystksz = 0;
+ yyGrowStack(pParser);
+#endif
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(
+ yyParser *yypParser, /* The parser */
+ YYCODETYPE yymajor, /* Type code for object to destroy */
+ YYMINORTYPE *yypminor /* The object to be destroyed */
+){
+ sqlite2_parseARG_FETCH;
+ if (parserContext->executeRules)
+ {
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+ case 148: /* cmd */
+ case 151: /* ecmd */
+ case 153: /* cmdx */
+ case 191: /* select_stmt */
+ case 214: /* delete_stmt */
+ case 215: /* update_stmt */
+ case 217: /* insert_stmt */
+ case 237: /* trigger_cmd */
+{
+delete (yypminor->yy203);
+}
+ break;
+ case 152: /* explain */
+{
+delete (yypminor->yy91);
+}
+ break;
+ case 154: /* trans_opt */
+{
+delete (yypminor->yy404);
+}
+ break;
+ case 155: /* onconf */
+ case 189: /* resolvetype */
+ case 190: /* orconf */
+{
+delete (yypminor->yy418);
+}
+ break;
+ case 156: /* nm */
+ case 163: /* columnid */
+ case 166: /* id */
+ case 167: /* ids */
+ case 169: /* typename */
+ case 209: /* dbnm */
+{
+delete (yypminor->yy319);
+}
+ break;
+ case 157: /* temp */
+ case 194: /* distinct */
+{
+delete (yypminor->yy226);
+}
+ break;
+ case 158: /* fullname */
+{
+delete (yypminor->yy120);
+}
+ break;
+ case 159: /* columnlist */
+{
+delete (yypminor->yy42);
+}
+ break;
+ case 160: /* conslist_opt */
+ case 184: /* conslist */
+{
+delete (yypminor->yy13);
+}
+ break;
+ case 161: /* select */
+{
+delete (yypminor->yy153);
+}
+ break;
+ case 162: /* column */
+{
+delete (yypminor->yy147);
+}
+ break;
+ case 164: /* type */
+ case 168: /* typetoken */
+{
+delete (yypminor->yy57);
+}
+ break;
+ case 165: /* carglist */
+{
+delete (yypminor->yy371);
+}
+ break;
+ case 170: /* signed */
+ case 171: /* plus_num */
+ case 172: /* minus_num */
+ case 230: /* nmnum */
+ case 231: /* number */
+{
+delete (yypminor->yy69);
+}
+ break;
+ case 173: /* ccons */
+ case 174: /* ccons_nm */
+ case 175: /* carg */
+{
+delete (yypminor->yy304);
+}
+ break;
+ case 176: /* sortorder */
+{
+delete (yypminor->yy389);
+}
+ break;
+ case 177: /* expr */
+ case 197: /* where_opt */
+ case 199: /* having_opt */
+ case 221: /* exprx */
+ case 224: /* case_operand */
+ case 226: /* case_else */
+{
+delete (yypminor->yy192);
+}
+ break;
+ case 178: /* idxlist_opt */
+ case 187: /* idxlist */
+{
+delete (yypminor->yy63);
+}
+ break;
+ case 179: /* refargs */
+{
+delete (yypminor->yy264);
+}
+ break;
+ case 180: /* defer_subclause */
+ case 188: /* defer_subclause_opt */
+{
+delete (yypminor->yy329);
+}
+ break;
+ case 181: /* refarg */
+{
+delete (yypminor->yy187);
+}
+ break;
+ case 182: /* refact */
+{
+delete (yypminor->yy424);
+}
+ break;
+ case 183: /* init_deferred_pred_opt */
+{
+delete (yypminor->yy312);
+}
+ break;
+ case 185: /* tconscomma */
+ case 222: /* not_opt */
+ case 228: /* uniqueflag */
+ case 238: /* database_kw_opt */
+{
+delete (yypminor->yy291);
+}
+ break;
+ case 186: /* tcons */
+{
+delete (yypminor->yy406);
+}
+ break;
+ case 192: /* oneselect */
+{
+delete (yypminor->yy150);
+}
+ break;
+ case 193: /* multiselect_op */
+{
+delete (yypminor->yy382);
+}
+ break;
+ case 195: /* selcollist */
+ case 202: /* sclp */
+{
+delete (yypminor->yy213);
+}
+ break;
+ case 196: /* from */
+ case 204: /* joinsrc */
+{
+delete (yypminor->yy31);
+}
+ break;
+ case 198: /* groupby_opt */
+ case 213: /* nexprlist */
+ case 220: /* exprlist */
+ case 225: /* case_exprlist */
+{
+delete (yypminor->yy231);
+}
+ break;
+ case 200: /* orderby_opt */
+ case 211: /* sortlist */
+{
+delete (yypminor->yy243);
+}
+ break;
+ case 201: /* limit_opt */
+{
+delete (yypminor->yy324);
+}
+ break;
+ case 203: /* as */
+{
+delete (yypminor->yy40);
+}
+ break;
+ case 205: /* singlesrc */
+{
+delete (yypminor->yy121);
+}
+ break;
+ case 206: /* seltablist */
+{
+delete (yypminor->yy131);
+}
+ break;
+ case 207: /* joinop */
+{
+delete (yypminor->yy221);
+}
+ break;
+ case 208: /* joinconstr_opt */
+{
+delete (yypminor->yy455);
+}
+ break;
+ case 210: /* inscollist */
+ case 219: /* inscollist_opt */
+{
+delete (yypminor->yy207);
+}
+ break;
+ case 212: /* collate */
+{
+if ((yypminor->yy319)) delete (yypminor->yy319);
+}
+ break;
+ case 216: /* setlist */
+{
+delete (yypminor->yy201);
+}
+ break;
+ case 218: /* insert_cmd */
+{
+delete (yypminor->yy344);
+}
+ break;
+ case 223: /* likeop */
+{
+delete (yypminor->yy41);
+}
+ break;
+ case 229: /* idxlist_single */
+{
+delete (yypminor->yy428);
+}
+ break;
+ case 232: /* trigger_time */
+{
+delete (yypminor->yy372);
+}
+ break;
+ case 233: /* trigger_event */
+{
+delete (yypminor->yy151);
+}
+ break;
+ case 234: /* foreach_clause */
+{
+delete (yypminor->yy83);
+}
+ break;
+ case 235: /* when_clause */
+ case 239: /* key_opt */
+{
+if ((yypminor->yy192)) delete (yypminor->yy192);
+}
+ break;
+ case 236: /* trigger_cmd_list */
+{
+delete (yypminor->yy270);
+}
+ break;
+ default: break; /* If no destructor action specified: do nothing */
+ }
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+ /* There is no mechanism by which the parser stack can be popped below
+ ** empty in SQLite. */
+ if( pParser->yyidx<0 ) return 0;
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor(pParser, yymajor, &yytos->minor);
+ delete yytos->tokens;
+ yytos->tokens = nullptr;
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from sqlite2_parseAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void sqlite2_parseFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ /* In SQLite, we never try to destroy a parser that was not successfully
+ ** created in the first place. */
+ if( pParser==0 ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int sqlite2_parseStackPeak(void *p){
+ yyParser *pParser = (yyParser*)p;
+ return pParser->yyidxMax;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+ GET_CONTEXT;
+
+ if( stateno>YY_SHIFT_COUNT
+ || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
+#ifdef YYFALLBACK
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0
+ && parserContext->doFallbacks ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
+#if YY_SHIFT_MIN+YYWILDCARD<0
+ j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+ j<YY_ACTTAB_COUNT &&
+#endif
+ yy_lookahead[j]==YYWILDCARD
+ ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
+ }
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ int stateno, /* Current state number */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+#ifdef YYERRORSYMBOL
+ if( stateno>YY_REDUCE_COUNT ){
+ return yy_default[stateno];
+ }
+#else
+ assert( stateno<=YY_REDUCE_COUNT );
+#endif
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+#ifdef YYERRORSYMBOL
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }
+#else
+ assert( i>=0 && i<YY_ACTTAB_COUNT );
+ assert( yy_lookahead[i]==iLookAhead );
+#endif
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ sqlite2_parseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+
+ UNUSED_PARAMETER(yypMinor);
+ parserContext->error(QObject::tr("Parser stack overflow"));
+ sqlite2_parseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( yypParser->yyidx>yypParser->yyidxMax ){
+ yypParser->yyidxMax = yypParser->yyidx;
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = (YYACTIONTYPE)yyNewState;
+ yytos->major = (YYCODETYPE)yyMajor;
+ yytos->minor = *yypMinor;
+ yytos->tokens = new QList<Token*>();
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 149, 1 },
+ { 150, 2 },
+ { 150, 1 },
+ { 151, 1 },
+ { 151, 3 },
+ { 152, 0 },
+ { 152, 1 },
+ { 153, 1 },
+ { 148, 3 },
+ { 154, 0 },
+ { 154, 1 },
+ { 154, 2 },
+ { 154, 2 },
+ { 148, 2 },
+ { 148, 2 },
+ { 148, 2 },
+ { 148, 8 },
+ { 148, 6 },
+ { 148, 6 },
+ { 148, 4 },
+ { 157, 1 },
+ { 157, 0 },
+ { 159, 3 },
+ { 159, 1 },
+ { 162, 3 },
+ { 163, 1 },
+ { 163, 1 },
+ { 166, 1 },
+ { 167, 1 },
+ { 156, 1 },
+ { 156, 1 },
+ { 156, 1 },
+ { 164, 0 },
+ { 164, 1 },
+ { 168, 1 },
+ { 168, 4 },
+ { 168, 6 },
+ { 169, 1 },
+ { 169, 2 },
+ { 169, 1 },
+ { 170, 1 },
+ { 170, 1 },
+ { 165, 2 },
+ { 165, 3 },
+ { 165, 2 },
+ { 165, 0 },
+ { 175, 2 },
+ { 175, 2 },
+ { 175, 2 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 2 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 2 },
+ { 174, 2 },
+ { 173, 2 },
+ { 173, 3 },
+ { 173, 4 },
+ { 173, 2 },
+ { 173, 5 },
+ { 173, 4 },
+ { 173, 1 },
+ { 173, 2 },
+ { 173, 3 },
+ { 179, 0 },
+ { 179, 2 },
+ { 181, 2 },
+ { 181, 3 },
+ { 181, 3 },
+ { 181, 3 },
+ { 181, 2 },
+ { 182, 2 },
+ { 182, 2 },
+ { 182, 1 },
+ { 182, 1 },
+ { 180, 3 },
+ { 180, 2 },
+ { 183, 0 },
+ { 183, 2 },
+ { 183, 2 },
+ { 160, 0 },
+ { 160, 2 },
+ { 184, 3 },
+ { 184, 1 },
+ { 185, 1 },
+ { 185, 0 },
+ { 186, 2 },
+ { 186, 6 },
+ { 186, 5 },
+ { 186, 5 },
+ { 186, 10 },
+ { 186, 2 },
+ { 186, 7 },
+ { 186, 4 },
+ { 188, 0 },
+ { 188, 1 },
+ { 155, 0 },
+ { 155, 3 },
+ { 190, 0 },
+ { 190, 2 },
+ { 189, 1 },
+ { 189, 1 },
+ { 189, 1 },
+ { 189, 1 },
+ { 189, 1 },
+ { 148, 3 },
+ { 148, 5 },
+ { 148, 3 },
+ { 148, 6 },
+ { 148, 4 },
+ { 148, 3 },
+ { 148, 3 },
+ { 148, 1 },
+ { 191, 1 },
+ { 161, 1 },
+ { 161, 3 },
+ { 193, 1 },
+ { 193, 2 },
+ { 193, 1 },
+ { 193, 1 },
+ { 192, 9 },
+ { 194, 1 },
+ { 194, 1 },
+ { 194, 0 },
+ { 202, 2 },
+ { 202, 0 },
+ { 195, 3 },
+ { 195, 2 },
+ { 195, 4 },
+ { 195, 1 },
+ { 195, 4 },
+ { 203, 2 },
+ { 203, 1 },
+ { 203, 2 },
+ { 203, 1 },
+ { 203, 0 },
+ { 196, 0 },
+ { 196, 2 },
+ { 204, 2 },
+ { 204, 0 },
+ { 206, 4 },
+ { 206, 0 },
+ { 205, 3 },
+ { 205, 4 },
+ { 205, 4 },
+ { 205, 0 },
+ { 205, 2 },
+ { 205, 3 },
+ { 205, 1 },
+ { 205, 3 },
+ { 205, 1 },
+ { 208, 2 },
+ { 208, 4 },
+ { 208, 0 },
+ { 209, 0 },
+ { 209, 2 },
+ { 158, 2 },
+ { 207, 1 },
+ { 207, 1 },
+ { 207, 2 },
+ { 207, 3 },
+ { 207, 4 },
+ { 207, 1 },
+ { 200, 0 },
+ { 200, 3 },
+ { 211, 5 },
+ { 211, 3 },
+ { 212, 0 },
+ { 212, 2 },
+ { 176, 1 },
+ { 176, 1 },
+ { 176, 0 },
+ { 198, 0 },
+ { 198, 3 },
+ { 198, 2 },
+ { 199, 0 },
+ { 199, 2 },
+ { 201, 0 },
+ { 201, 2 },
+ { 201, 4 },
+ { 201, 4 },
+ { 148, 1 },
+ { 214, 4 },
+ { 214, 2 },
+ { 214, 4 },
+ { 214, 5 },
+ { 214, 3 },
+ { 197, 0 },
+ { 197, 2 },
+ { 197, 1 },
+ { 148, 1 },
+ { 215, 6 },
+ { 215, 2 },
+ { 215, 4 },
+ { 215, 5 },
+ { 215, 3 },
+ { 216, 5 },
+ { 216, 3 },
+ { 216, 0 },
+ { 216, 2 },
+ { 216, 3 },
+ { 216, 1 },
+ { 148, 1 },
+ { 217, 8 },
+ { 217, 5 },
+ { 217, 2 },
+ { 217, 4 },
+ { 217, 3 },
+ { 217, 5 },
+ { 218, 2 },
+ { 218, 1 },
+ { 219, 0 },
+ { 219, 3 },
+ { 210, 3 },
+ { 210, 1 },
+ { 210, 0 },
+ { 210, 3 },
+ { 210, 1 },
+ { 221, 1 },
+ { 221, 1 },
+ { 221, 1 },
+ { 221, 1 },
+ { 221, 3 },
+ { 221, 1 },
+ { 221, 1 },
+ { 221, 3 },
+ { 221, 5 },
+ { 221, 1 },
+ { 221, 4 },
+ { 221, 4 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 3 },
+ { 221, 4 },
+ { 221, 2 },
+ { 221, 3 },
+ { 221, 4 },
+ { 221, 2 },
+ { 221, 2 },
+ { 221, 2 },
+ { 221, 2 },
+ { 221, 6 },
+ { 221, 6 },
+ { 221, 6 },
+ { 221, 5 },
+ { 221, 3 },
+ { 221, 5 },
+ { 221, 6 },
+ { 221, 4 },
+ { 221, 2 },
+ { 221, 4 },
+ { 221, 4 },
+ { 221, 4 },
+ { 221, 5 },
+ { 221, 4 },
+ { 221, 6 },
+ { 221, 1 },
+ { 221, 3 },
+ { 221, 5 },
+ { 221, 6 },
+ { 177, 1 },
+ { 177, 0 },
+ { 222, 0 },
+ { 222, 1 },
+ { 223, 1 },
+ { 225, 5 },
+ { 225, 4 },
+ { 226, 2 },
+ { 226, 0 },
+ { 224, 1 },
+ { 224, 0 },
+ { 220, 1 },
+ { 220, 0 },
+ { 213, 3 },
+ { 213, 1 },
+ { 148, 11 },
+ { 148, 7 },
+ { 148, 6 },
+ { 148, 4 },
+ { 228, 1 },
+ { 228, 0 },
+ { 178, 0 },
+ { 178, 3 },
+ { 187, 3 },
+ { 187, 1 },
+ { 229, 2 },
+ { 229, 1 },
+ { 148, 3 },
+ { 148, 5 },
+ { 148, 3 },
+ { 148, 9 },
+ { 148, 6 },
+ { 148, 1 },
+ { 148, 2 },
+ { 148, 2 },
+ { 148, 4 },
+ { 148, 5 },
+ { 148, 4 },
+ { 148, 5 },
+ { 148, 4 },
+ { 148, 2 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 171, 2 },
+ { 171, 1 },
+ { 172, 2 },
+ { 231, 1 },
+ { 231, 1 },
+ { 148, 14 },
+ { 148, 11 },
+ { 148, 13 },
+ { 148, 8 },
+ { 148, 10 },
+ { 148, 4 },
+ { 232, 1 },
+ { 232, 1 },
+ { 232, 2 },
+ { 232, 0 },
+ { 233, 1 },
+ { 233, 1 },
+ { 233, 1 },
+ { 233, 3 },
+ { 234, 0 },
+ { 234, 3 },
+ { 234, 3 },
+ { 235, 0 },
+ { 235, 2 },
+ { 236, 3 },
+ { 236, 2 },
+ { 237, 1 },
+ { 237, 1 },
+ { 237, 1 },
+ { 237, 1 },
+ { 227, 1 },
+ { 148, 3 },
+ { 148, 5 },
+ { 148, 3 },
+ { 148, 6 },
+ { 239, 0 },
+ { 239, 2 },
+ { 238, 1 },
+ { 238, 0 },
+ { 148, 3 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ sqlite2_parseARG_FETCH;
+ SqliteStatement* objectForTokens = 0;
+ QStringList noTokenInheritanceFields;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && yyruleno>=0
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ }
+#endif /* NDEBUG */
+
+ /* Silence complaints from purify about yygotominor being uninitialized
+ ** in some cases when it is copied into the stack after the following
+ ** switch. yygotominor is uninitialized when a rule reduces that does
+ ** not set the value of its left-hand side nonterminal. Leaving the
+ ** value of the nonterminal uninitialized is utterly harmless as long
+ ** as the value is never used. So really the only thing this code
+ ** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
+ */
+ /*memset(&yygotominor, 0, sizeof(yygotominor));*/
+ yygotominor = yyzerominor;
+
+
+ if (parserContext->executeRules)
+ {
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+ case 1: /* cmdlist ::= cmdlist ecmd */
+{parserContext->addQuery(yymsp[0].minor.yy203); DONT_INHERIT_TOKENS("cmdlist");}
+ break;
+ case 2: /* cmdlist ::= ecmd */
+{parserContext->addQuery(yymsp[0].minor.yy203);}
+ break;
+ case 3: /* ecmd ::= SEMI */
+{yygotominor.yy203 = new SqliteEmptyQuery();}
+ break;
+ case 4: /* ecmd ::= explain cmdx SEMI */
+{
+ yygotominor.yy203 = yymsp[-1].minor.yy203;
+ yygotominor.yy203->explain = yymsp[-2].minor.yy91->explain;
+ yygotominor.yy203->queryPlan = yymsp[-2].minor.yy91->queryPlan;
+ delete yymsp[-2].minor.yy91;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 5: /* explain ::= */
+{yygotominor.yy91 = new ParserStubExplain(false, false);}
+ break;
+ case 6: /* explain ::= EXPLAIN */
+{yygotominor.yy91 = new ParserStubExplain(true, false);}
+ break;
+ case 7: /* cmdx ::= cmd */
+ case 338: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==338);
+ case 339: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==339);
+ case 340: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==340);
+ case 341: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==341);
+{yygotominor.yy203 = yymsp[0].minor.yy203;}
+ break;
+ case 8: /* cmd ::= BEGIN trans_opt onconf */
+{
+ yygotominor.yy203 = new SqliteBeginTrans(
+ yymsp[-1].minor.yy404->transactionKw,
+ yymsp[-1].minor.yy404->name,
+ *(yymsp[0].minor.yy418)
+ );
+ delete yymsp[-1].minor.yy404;
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 9: /* trans_opt ::= */
+{yygotominor.yy404 = new ParserStubTransDetails();}
+ break;
+ case 10: /* trans_opt ::= TRANSACTION */
+{
+ yygotominor.yy404 = new ParserStubTransDetails();
+ yygotominor.yy404->transactionKw = true;
+ }
+ break;
+ case 11: /* trans_opt ::= TRANSACTION nm */
+ case 12: /* trans_opt ::= TRANSACTION ID_TRANS */ yytestcase(yyruleno==12);
+{
+ yygotominor.yy404 = new ParserStubTransDetails();
+ yygotominor.yy404->transactionKw = true;
+ yygotominor.yy404->name = *(yymsp[0].minor.yy319);
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 13: /* cmd ::= COMMIT trans_opt */
+{
+ yygotominor.yy203 = new SqliteCommitTrans(
+ yymsp[0].minor.yy404->transactionKw,
+ yymsp[0].minor.yy404->name,
+ false
+ );
+ delete yymsp[0].minor.yy404;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 14: /* cmd ::= END trans_opt */
+{
+ yygotominor.yy203 = new SqliteCommitTrans(
+ yymsp[0].minor.yy404->transactionKw,
+ yymsp[0].minor.yy404->name,
+ true
+ );
+ delete yymsp[0].minor.yy404;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 15: /* cmd ::= ROLLBACK trans_opt */
+{
+ yygotominor.yy203 = new SqliteRollback(
+ yymsp[0].minor.yy404->transactionKw,
+ yymsp[0].minor.yy404->name
+ );
+ delete yymsp[0].minor.yy404;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 16: /* cmd ::= CREATE temp TABLE fullname LP columnlist conslist_opt RP */
+{
+ yygotominor.yy203 = new SqliteCreateTable(
+ *(yymsp[-6].minor.yy226),
+ false,
+ yymsp[-4].minor.yy120->name1,
+ yymsp[-4].minor.yy120->name2,
+ *(yymsp[-2].minor.yy42),
+ *(yymsp[-1].minor.yy13)
+ );
+ delete yymsp[-6].minor.yy226;
+ delete yymsp[-2].minor.yy42;
+ delete yymsp[-1].minor.yy13;
+ delete yymsp[-4].minor.yy120;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 17: /* cmd ::= CREATE temp TABLE fullname AS select */
+{
+ yygotominor.yy203 = new SqliteCreateTable(
+ *(yymsp[-4].minor.yy226),
+ false,
+ yymsp[-2].minor.yy120->name1,
+ yymsp[-2].minor.yy120->name2,
+ yymsp[0].minor.yy153
+ );
+ delete yymsp[-4].minor.yy226;
+ delete yymsp[-2].minor.yy120;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 18: /* cmd ::= CREATE temp TABLE nm DOT ID_TAB_NEW */
+{ yy_destructor(yypParser,157,&yymsp[-4].minor);
+ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 19: /* cmd ::= CREATE temp TABLE ID_DB|ID_TAB_NEW */
+ case 110: /* cmd ::= CREATE temp VIEW ID_VIEW_NEW */ yytestcase(yyruleno==110);
+ case 322: /* cmd ::= CREATE temp TRIGGER ID_TRIG_NEW */ yytestcase(yyruleno==322);
+{ yy_destructor(yypParser,157,&yymsp[-2].minor);
+}
+ break;
+ case 20: /* temp ::= TEMP */
+{yygotominor.yy226 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );}
+ break;
+ case 21: /* temp ::= */
+ case 124: /* distinct ::= */ yytestcase(yyruleno==124);
+{yygotominor.yy226 = new int(0);}
+ break;
+ case 22: /* columnlist ::= columnlist COMMA column */
+{
+ yymsp[-2].minor.yy42->append(yymsp[0].minor.yy147);
+ yygotominor.yy42 = yymsp[-2].minor.yy42;
+ DONT_INHERIT_TOKENS("columnlist");
+ }
+ break;
+ case 23: /* columnlist ::= column */
+{
+ yygotominor.yy42 = new ParserCreateTableColumnList();
+ yygotominor.yy42->append(yymsp[0].minor.yy147);
+ }
+ break;
+ case 24: /* column ::= columnid type carglist */
+{
+ yygotominor.yy147 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy319), yymsp[-1].minor.yy57, *(yymsp[0].minor.yy371));
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy371;
+ objectForTokens = yygotominor.yy147;
+ }
+ break;
+ case 25: /* columnid ::= nm */
+ case 26: /* columnid ::= ID_COL_NEW */ yytestcase(yyruleno==26);
+ case 29: /* nm ::= id */ yytestcase(yyruleno==29);
+ case 37: /* typename ::= ids */ yytestcase(yyruleno==37);
+ case 156: /* dbnm ::= DOT nm */ yytestcase(yyruleno==156);
+ case 169: /* collate ::= COLLATE id */ yytestcase(yyruleno==169);
+{yygotominor.yy319 = yymsp[0].minor.yy319;}
+ break;
+ case 27: /* id ::= ID */
+{
+ yygotominor.yy319 = new QString(
+ stripObjName(
+ yymsp[0].minor.yy0->value,
+ parserContext->dialect
+ )
+ );
+ }
+ break;
+ case 28: /* ids ::= ID|STRING */
+ case 31: /* nm ::= JOIN_KW */ yytestcase(yyruleno==31);
+{yygotominor.yy319 = new QString(yymsp[0].minor.yy0->value);}
+ break;
+ case 30: /* nm ::= STRING */
+{yygotominor.yy319 = new QString(stripString(yymsp[0].minor.yy0->value));}
+ break;
+ case 32: /* type ::= */
+{yygotominor.yy57 = nullptr;}
+ break;
+ case 33: /* type ::= typetoken */
+{yygotominor.yy57 = yymsp[0].minor.yy57;}
+ break;
+ case 34: /* typetoken ::= typename */
+{
+ yygotominor.yy57 = new SqliteColumnType(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy57;
+ }
+ break;
+ case 35: /* typetoken ::= typename LP signed RP */
+{
+ yygotominor.yy57 = new SqliteColumnType(*(yymsp[-3].minor.yy319), *(yymsp[-1].minor.yy69));
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-1].minor.yy69;
+ objectForTokens = yygotominor.yy57;
+ }
+ break;
+ case 36: /* typetoken ::= typename LP signed COMMA signed RP */
+{
+ yygotominor.yy57 = new SqliteColumnType(*(yymsp[-5].minor.yy319), *(yymsp[-3].minor.yy69), *(yymsp[-1].minor.yy69));
+ delete yymsp[-5].minor.yy319;
+ delete yymsp[-3].minor.yy69;
+ delete yymsp[-1].minor.yy69;
+ objectForTokens = yygotominor.yy57;
+ }
+ break;
+ case 38: /* typename ::= typename ids */
+ case 39: /* typename ::= ID_COL_TYPE */ yytestcase(yyruleno==39);
+{
+ yymsp[-1].minor.yy319->append(" " + *(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ yygotominor.yy319 = yymsp[-1].minor.yy319;
+ }
+ break;
+ case 40: /* signed ::= plus_num */
+ case 41: /* signed ::= minus_num */ yytestcase(yyruleno==41);
+ case 307: /* nmnum ::= plus_num */ yytestcase(yyruleno==307);
+ case 312: /* plus_num ::= PLUS number */ yytestcase(yyruleno==312);
+ case 313: /* plus_num ::= number */ yytestcase(yyruleno==313);
+{yygotominor.yy69 = yymsp[0].minor.yy69;}
+ break;
+ case 42: /* carglist ::= carglist ccons */
+ case 44: /* carglist ::= carglist carg */ yytestcase(yyruleno==44);
+{
+ yymsp[-1].minor.yy371->append(yymsp[0].minor.yy304);
+ yygotominor.yy371 = yymsp[-1].minor.yy371;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+ break;
+ case 43: /* carglist ::= carglist ccons_nm ccons */
+{
+ yymsp[-2].minor.yy371->append(yymsp[-1].minor.yy304);
+ yymsp[-2].minor.yy371->append(yymsp[0].minor.yy304);
+ yygotominor.yy371 = yymsp[-2].minor.yy371;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+ break;
+ case 45: /* carglist ::= */
+{yygotominor.yy371 = new ParserCreateTableColumnConstraintList();}
+ break;
+ case 46: /* carg ::= DEFAULT STRING */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initDefId(stripObjName(
+ yymsp[0].minor.yy0->value,
+ parserContext->dialect
+ ));
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 47: /* carg ::= DEFAULT ID */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initDefId(stripObjName(
+ yymsp[0].minor.yy0->value,
+ parserContext->dialect
+ ));
+ objectForTokens = yygotominor.yy304;
+
+ }
+ break;
+ case 48: /* carg ::= DEFAULT INTEGER */
+ case 49: /* carg ::= DEFAULT PLUS INTEGER */ yytestcase(yyruleno==49);
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toLongLong();
+ yygotominor.yy304->initDefTerm(val, false);
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 50: /* carg ::= DEFAULT MINUS INTEGER */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toLongLong();
+ yygotominor.yy304->initDefTerm(val, true);
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 51: /* carg ::= DEFAULT FLOAT */
+ case 52: /* carg ::= DEFAULT PLUS FLOAT */ yytestcase(yyruleno==52);
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toDouble();
+ yygotominor.yy304->initDefTerm(val, false);
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 53: /* carg ::= DEFAULT MINUS FLOAT */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toDouble();
+ yygotominor.yy304->initDefTerm(val, true);
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 54: /* carg ::= DEFAULT NULL */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initDefTerm(QVariant(), false);
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 55: /* ccons_nm ::= CONSTRAINT nm */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initDefNameOnly(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 56: /* ccons ::= NULL onconf */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initNull(*(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 57: /* ccons ::= NOT NULL onconf */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initNotNull(*(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 58: /* ccons ::= PRIMARY KEY sortorder onconf */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initPk(*(yymsp[-1].minor.yy389), *(yymsp[0].minor.yy418), false);
+ delete yymsp[-1].minor.yy389;
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 59: /* ccons ::= UNIQUE onconf */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initUnique(*(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 60: /* ccons ::= CHECK LP expr RP onconf */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initCheck(yymsp[-2].minor.yy192, *(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 61: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initFk(*(yymsp[-2].minor.yy319), *(yymsp[-1].minor.yy63), *(yymsp[0].minor.yy264));
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy264;
+ delete yymsp[-1].minor.yy63;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 62: /* ccons ::= defer_subclause */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initDefer(yymsp[0].minor.yy329->initially, yymsp[0].minor.yy329->deferrable);
+ delete yymsp[0].minor.yy329;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 63: /* ccons ::= COLLATE id */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initColl(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy304;
+ }
+ break;
+ case 64: /* ccons ::= CHECK LP RP */
+{
+ yygotominor.yy304 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy304->initCheck();
+ objectForTokens = yygotominor.yy304;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 65: /* refargs ::= */
+{yygotominor.yy264 = new ParserFkConditionList();}
+ break;
+ case 66: /* refargs ::= refargs refarg */
+{
+ yymsp[-1].minor.yy264->append(yymsp[0].minor.yy187);
+ yygotominor.yy264 = yymsp[-1].minor.yy264;
+ DONT_INHERIT_TOKENS("refargs");
+ }
+ break;
+ case 67: /* refarg ::= MATCH nm */
+{
+ yygotominor.yy187 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 68: /* refarg ::= ON INSERT refact */
+{yygotominor.yy187 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy424)); delete yymsp[0].minor.yy424;}
+ break;
+ case 69: /* refarg ::= ON DELETE refact */
+{yygotominor.yy187 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy424)); delete yymsp[0].minor.yy424;}
+ break;
+ case 70: /* refarg ::= ON UPDATE refact */
+ case 71: /* refarg ::= MATCH ID_FK_MATCH */ yytestcase(yyruleno==71);
+{yygotominor.yy187 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy424)); delete yymsp[0].minor.yy424;}
+ break;
+ case 72: /* refact ::= SET NULL */
+{yygotominor.yy424 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);}
+ break;
+ case 73: /* refact ::= SET DEFAULT */
+{yygotominor.yy424 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);}
+ break;
+ case 74: /* refact ::= CASCADE */
+{yygotominor.yy424 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);}
+ break;
+ case 75: /* refact ::= RESTRICT */
+{yygotominor.yy424 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);}
+ break;
+ case 76: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+{
+ yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy312));
+ delete yymsp[0].minor.yy312;
+ }
+ break;
+ case 77: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+{
+ yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy312));
+ delete yymsp[0].minor.yy312;
+ }
+ break;
+ case 78: /* init_deferred_pred_opt ::= */
+{yygotominor.yy312 = new SqliteInitially(SqliteInitially::null);}
+ break;
+ case 79: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+{yygotominor.yy312 = new SqliteInitially(SqliteInitially::DEFERRED);}
+ break;
+ case 80: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+{yygotominor.yy312 = new SqliteInitially(SqliteInitially::IMMEDIATE);}
+ break;
+ case 81: /* conslist_opt ::= */
+{yygotominor.yy13 = new ParserCreateTableConstraintList();}
+ break;
+ case 82: /* conslist_opt ::= COMMA conslist */
+{yygotominor.yy13 = yymsp[0].minor.yy13;}
+ break;
+ case 83: /* conslist ::= conslist tconscomma tcons */
+{
+ yymsp[0].minor.yy406->afterComma = *(yymsp[-1].minor.yy291);
+ yymsp[-2].minor.yy13->append(yymsp[0].minor.yy406);
+ yygotominor.yy13 = yymsp[-2].minor.yy13;
+ delete yymsp[-1].minor.yy291;
+ DONT_INHERIT_TOKENS("conslist");
+ }
+ break;
+ case 84: /* conslist ::= tcons */
+{
+ yygotominor.yy13 = new ParserCreateTableConstraintList();
+ yygotominor.yy13->append(yymsp[0].minor.yy406);
+ }
+ break;
+ case 85: /* tconscomma ::= COMMA */
+ case 269: /* not_opt ::= NOT */ yytestcase(yyruleno==269);
+ case 285: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==285);
+ case 349: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==349);
+{yygotominor.yy291 = new bool(true);}
+ break;
+ case 86: /* tconscomma ::= */
+ case 268: /* not_opt ::= */ yytestcase(yyruleno==268);
+ case 286: /* uniqueflag ::= */ yytestcase(yyruleno==286);
+ case 350: /* database_kw_opt ::= */ yytestcase(yyruleno==350);
+{yygotominor.yy291 = new bool(false);}
+ break;
+ case 87: /* tcons ::= CONSTRAINT nm */
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initNameOnly(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy406;
+ }
+ break;
+ case 88: /* tcons ::= PRIMARY KEY LP idxlist RP onconf */
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initPk(*(yymsp[-2].minor.yy63), false, *(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ delete yymsp[-2].minor.yy63;
+ objectForTokens = yygotominor.yy406;
+ }
+ break;
+ case 89: /* tcons ::= UNIQUE LP idxlist RP onconf */
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initUnique(*(yymsp[-2].minor.yy63), *(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ delete yymsp[-2].minor.yy63;
+ objectForTokens = yygotominor.yy406;
+ }
+ break;
+ case 90: /* tcons ::= CHECK LP expr RP onconf */
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initCheck(yymsp[-2].minor.yy192, *(yymsp[0].minor.yy418));
+ objectForTokens = yygotominor.yy406;
+ }
+ break;
+ case 91: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
+ case 92: /* tcons ::= CONSTRAINT ID_CONSTR */ yytestcase(yyruleno==92);
+ case 93: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB */ yytestcase(yyruleno==93);
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initFk(
+ *(yymsp[-6].minor.yy63),
+ *(yymsp[-3].minor.yy319),
+ *(yymsp[-2].minor.yy63),
+ *(yymsp[-1].minor.yy264),
+ yymsp[0].minor.yy329->initially,
+ yymsp[0].minor.yy329->deferrable
+ );
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-1].minor.yy264;
+ delete yymsp[0].minor.yy329;
+ delete yymsp[-2].minor.yy63;
+ delete yymsp[-6].minor.yy63;
+ objectForTokens = yygotominor.yy406;
+ }
+ break;
+ case 94: /* tcons ::= CHECK LP RP onconf */
+{
+ yygotominor.yy406 = new SqliteCreateTable::Constraint();
+ yygotominor.yy406->initCheck();
+ objectForTokens = yygotominor.yy406;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ yy_destructor(yypParser,155,&yymsp[0].minor);
+}
+ break;
+ case 95: /* defer_subclause_opt ::= */
+{yygotominor.yy329 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);}
+ break;
+ case 96: /* defer_subclause_opt ::= defer_subclause */
+{yygotominor.yy329 = yymsp[0].minor.yy329;}
+ break;
+ case 97: /* onconf ::= */
+ case 99: /* orconf ::= */ yytestcase(yyruleno==99);
+{yygotominor.yy418 = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+ break;
+ case 98: /* onconf ::= ON CONFLICT resolvetype */
+ case 100: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==100);
+{yygotominor.yy418 = yymsp[0].minor.yy418;}
+ break;
+ case 101: /* resolvetype ::= ROLLBACK */
+ case 102: /* resolvetype ::= ABORT */ yytestcase(yyruleno==102);
+ case 103: /* resolvetype ::= FAIL */ yytestcase(yyruleno==103);
+ case 104: /* resolvetype ::= IGNORE */ yytestcase(yyruleno==104);
+ case 105: /* resolvetype ::= REPLACE */ yytestcase(yyruleno==105);
+{yygotominor.yy418 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));}
+ break;
+ case 106: /* cmd ::= DROP TABLE fullname */
+{
+ yygotominor.yy203 = new SqliteDropTable(false, yymsp[0].minor.yy120->name1, yymsp[0].minor.yy120->name2);
+ delete yymsp[0].minor.yy120;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 107: /* cmd ::= DROP TABLE nm DOT ID_TAB */
+ case 108: /* cmd ::= DROP TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==108);
+ case 148: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==148);
+ case 149: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==149);
+ case 150: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==150);
+ case 151: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==151);
+ case 186: /* delete_stmt ::= DELETE FROM nm DOT ID_TAB */ yytestcase(yyruleno==186);
+ case 187: /* delete_stmt ::= DELETE FROM ID_DB|ID_TAB */ yytestcase(yyruleno==187);
+ case 195: /* update_stmt ::= UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==195);
+ case 196: /* update_stmt ::= UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==196);
+ case 263: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==263);
+ case 283: /* cmd ::= CREATE uniqueflag INDEX nm DOT ID_IDX_NEW */ yytestcase(yyruleno==283);
+ case 284: /* cmd ::= CREATE uniqueflag INDEX ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==284);
+ case 294: /* cmd ::= DROP INDEX nm DOT ID_IDX */ yytestcase(yyruleno==294);
+ case 295: /* cmd ::= DROP INDEX ID_DB|ID_IDX */ yytestcase(yyruleno==295);
+ case 305: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==305);
+ case 306: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==306);
+ case 344: /* cmd ::= DROP TRIGGER nm DOT ID_TRIG */ yytestcase(yyruleno==344);
+ case 345: /* cmd ::= DROP TRIGGER ID_DB|ID_TRIG */ yytestcase(yyruleno==345);
+{ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 109: /* cmd ::= CREATE temp VIEW nm AS select */
+{
+ yygotominor.yy203 = new SqliteCreateView(*(yymsp[-4].minor.yy226), false, *(yymsp[-2].minor.yy319), QString::null, yymsp[0].minor.yy153);
+ delete yymsp[-4].minor.yy226;
+ delete yymsp[-2].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 111: /* cmd ::= DROP VIEW nm */
+ case 112: /* cmd ::= DROP VIEW ID_VIEW */ yytestcase(yyruleno==112);
+{
+ yygotominor.yy203 = new SqliteDropView(false, *(yymsp[0].minor.yy319), QString::null);
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 113: /* cmd ::= select_stmt */
+ case 182: /* cmd ::= delete_stmt */ yytestcase(yyruleno==182);
+ case 191: /* cmd ::= update_stmt */ yytestcase(yyruleno==191);
+ case 203: /* cmd ::= insert_stmt */ yytestcase(yyruleno==203);
+{
+ yygotominor.yy203 = yymsp[0].minor.yy203;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 114: /* select_stmt ::= select */
+{
+ yygotominor.yy203 = yymsp[0].minor.yy153;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 115: /* select ::= oneselect */
+{
+ yygotominor.yy153 = SqliteSelect::append(yymsp[0].minor.yy150);
+ objectForTokens = yygotominor.yy153;
+ }
+ break;
+ case 116: /* select ::= select multiselect_op oneselect */
+{
+ yygotominor.yy153 = SqliteSelect::append(yymsp[-2].minor.yy153, *(yymsp[-1].minor.yy382), yymsp[0].minor.yy150);
+ delete yymsp[-1].minor.yy382;
+ objectForTokens = yygotominor.yy153;
+ }
+ break;
+ case 117: /* multiselect_op ::= UNION */
+{yygotominor.yy382 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);}
+ break;
+ case 118: /* multiselect_op ::= UNION ALL */
+{yygotominor.yy382 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);}
+ break;
+ case 119: /* multiselect_op ::= EXCEPT */
+{yygotominor.yy382 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);}
+ break;
+ case 120: /* multiselect_op ::= INTERSECT */
+{yygotominor.yy382 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);}
+ break;
+ case 121: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+{
+ yygotominor.yy150 = new SqliteSelect::Core(
+ *(yymsp[-7].minor.yy226),
+ *(yymsp[-6].minor.yy213),
+ yymsp[-5].minor.yy31,
+ yymsp[-4].minor.yy192,
+ *(yymsp[-3].minor.yy231),
+ yymsp[-2].minor.yy192,
+ *(yymsp[-1].minor.yy243),
+ yymsp[0].minor.yy324
+ );
+ delete yymsp[-6].minor.yy213;
+ delete yymsp[-7].minor.yy226;
+ delete yymsp[-3].minor.yy231;
+ delete yymsp[-1].minor.yy243;
+ objectForTokens = yygotominor.yy150;
+ }
+ break;
+ case 122: /* distinct ::= DISTINCT */
+{yygotominor.yy226 = new int(1);}
+ break;
+ case 123: /* distinct ::= ALL */
+{yygotominor.yy226 = new int(2);}
+ break;
+ case 125: /* sclp ::= selcollist COMMA */
+{yygotominor.yy213 = yymsp[-1].minor.yy213;}
+ break;
+ case 126: /* sclp ::= */
+{yygotominor.yy213 = new ParserResultColumnList();}
+ break;
+ case 127: /* selcollist ::= sclp expr as */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ yymsp[-1].minor.yy192,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->asKw : false,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->name : QString::null
+ );
+
+ yymsp[-2].minor.yy213->append(obj);
+ yygotominor.yy213 = yymsp[-2].minor.yy213;
+ delete yymsp[0].minor.yy40;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 128: /* selcollist ::= sclp STAR */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(true);
+
+ yymsp[-1].minor.yy213->append(obj);
+ yygotominor.yy213 = yymsp[-1].minor.yy213;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 129: /* selcollist ::= sclp nm DOT STAR */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ true,
+ *(yymsp[-2].minor.yy319)
+ );
+ yymsp[-3].minor.yy213->append(obj);
+ yygotominor.yy213 = yymsp[-3].minor.yy213;
+ delete yymsp[-2].minor.yy319;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 130: /* selcollist ::= sclp */
+ case 131: /* selcollist ::= sclp ID_TAB DOT STAR */ yytestcase(yyruleno==131);
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy213 = yymsp[0].minor.yy213;
+ }
+ break;
+ case 132: /* as ::= AS nm */
+{
+ yygotominor.yy40 = new ParserStubAlias(*(yymsp[0].minor.yy319), true);
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 133: /* as ::= ids */
+ case 134: /* as ::= AS ID_ALIAS */ yytestcase(yyruleno==134);
+ case 135: /* as ::= ID_ALIAS */ yytestcase(yyruleno==135);
+{
+ yygotominor.yy40 = new ParserStubAlias(*(yymsp[0].minor.yy319), false);
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 136: /* as ::= */
+{yygotominor.yy40 = nullptr;}
+ break;
+ case 137: /* from ::= */
+{yygotominor.yy31 = nullptr;}
+ break;
+ case 138: /* from ::= FROM joinsrc */
+{yygotominor.yy31 = yymsp[0].minor.yy31;}
+ break;
+ case 139: /* joinsrc ::= singlesrc seltablist */
+{
+ yygotominor.yy31 = new SqliteSelect::Core::JoinSource(
+ yymsp[-1].minor.yy121,
+ *(yymsp[0].minor.yy131)
+ );
+ delete yymsp[0].minor.yy131;
+ objectForTokens = yygotominor.yy31;
+ }
+ break;
+ case 140: /* joinsrc ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy31 = new SqliteSelect::Core::JoinSource();
+ objectForTokens = yygotominor.yy31;
+ }
+ break;
+ case 141: /* seltablist ::= seltablist joinop singlesrc joinconstr_opt */
+{
+ SqliteSelect::Core::JoinSourceOther* src =
+ new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy221, yymsp[-1].minor.yy121, yymsp[0].minor.yy455);
+
+ yymsp[-3].minor.yy131->append(src);
+ yygotominor.yy131 = yymsp[-3].minor.yy131;
+ objectForTokens = src;
+ DONT_INHERIT_TOKENS("seltablist");
+ }
+ break;
+ case 142: /* seltablist ::= */
+{
+ yygotominor.yy131 = new ParserOtherSourceList();
+ }
+ break;
+ case 143: /* singlesrc ::= nm dbnm as */
+{
+ yygotominor.yy121 = new SqliteSelect::Core::SingleSource(
+ *(yymsp[-2].minor.yy319),
+ *(yymsp[-1].minor.yy319),
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->asKw : false,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->name : QString::null,
+ false,
+ QString::null
+ );
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[-1].minor.yy319;
+ delete yymsp[0].minor.yy40;
+ objectForTokens = yygotominor.yy121;
+ }
+ break;
+ case 144: /* singlesrc ::= LP select RP as */
+{
+ yygotominor.yy121 = new SqliteSelect::Core::SingleSource(
+ yymsp[-2].minor.yy153,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->asKw : false,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->name : QString::null
+ );
+ delete yymsp[0].minor.yy40;
+ objectForTokens = yygotominor.yy121;
+ }
+ break;
+ case 145: /* singlesrc ::= LP joinsrc RP as */
+{
+ yygotominor.yy121 = new SqliteSelect::Core::SingleSource(
+ yymsp[-2].minor.yy31,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->asKw : false,
+ yymsp[0].minor.yy40 ? yymsp[0].minor.yy40->name : QString::null
+ );
+ delete yymsp[0].minor.yy40;
+ objectForTokens = yygotominor.yy121;
+ }
+ break;
+ case 146: /* singlesrc ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy121 = new SqliteSelect::Core::SingleSource();
+ objectForTokens = yygotominor.yy121;
+ }
+ break;
+ case 147: /* singlesrc ::= nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy121 = new SqliteSelect::Core::SingleSource();
+ yygotominor.yy121->database = *(yymsp[-1].minor.yy319);
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy121;
+ }
+ break;
+ case 152: /* joinconstr_opt ::= ON expr */
+{
+ yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy192);
+ objectForTokens = yygotominor.yy455;
+ }
+ break;
+ case 153: /* joinconstr_opt ::= USING LP inscollist RP */
+{
+ yygotominor.yy455 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy207));
+ delete yymsp[-1].minor.yy207;
+ objectForTokens = yygotominor.yy455;
+ }
+ break;
+ case 154: /* joinconstr_opt ::= */
+{yygotominor.yy455 = nullptr;}
+ break;
+ case 155: /* dbnm ::= */
+{yygotominor.yy319 = new QString();}
+ break;
+ case 157: /* fullname ::= nm dbnm */
+{
+ yygotominor.yy120 = new ParserFullName();
+ yygotominor.yy120->name1 = *(yymsp[-1].minor.yy319);
+ yygotominor.yy120->name2 = *(yymsp[0].minor.yy319);
+ delete yymsp[-1].minor.yy319;
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 158: /* joinop ::= COMMA */
+{
+ yygotominor.yy221 = new SqliteSelect::Core::JoinOp(true);
+ objectForTokens = yygotominor.yy221;
+ }
+ break;
+ case 159: /* joinop ::= JOIN */
+{
+ yygotominor.yy221 = new SqliteSelect::Core::JoinOp(false);
+ objectForTokens = yygotominor.yy221;
+ }
+ break;
+ case 160: /* joinop ::= JOIN_KW JOIN */
+{
+ yygotominor.yy221 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy221;
+ }
+ break;
+ case 161: /* joinop ::= JOIN_KW nm JOIN */
+{
+ yygotominor.yy221 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy319));
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy221;
+ }
+ break;
+ case 162: /* joinop ::= JOIN_KW nm nm JOIN */
+ case 163: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==163);
+{
+ yygotominor.yy221 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy319), *(yymsp[-1].minor.yy319));
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[-2].minor.yy319;
+ objectForTokens = yygotominor.yy221;
+ }
+ break;
+ case 164: /* orderby_opt ::= */
+{yygotominor.yy243 = new ParserOrderByList();}
+ break;
+ case 165: /* orderby_opt ::= ORDER BY sortlist */
+{yygotominor.yy243 = yymsp[0].minor.yy243;}
+ break;
+ case 166: /* sortlist ::= sortlist COMMA collate expr sortorder */
+{
+ SqliteOrderBy* obj;
+ if (yymsp[-2].minor.yy319)
+ {
+ SqliteExpr* coll = new SqliteExpr();
+ coll->initCollate(yymsp[-1].minor.yy192, *(yymsp[-2].minor.yy319));
+ delete yymsp[-2].minor.yy319;
+ obj = new SqliteOrderBy(coll, *(yymsp[0].minor.yy389));
+ }
+ else
+ {
+ obj = new SqliteOrderBy(yymsp[-1].minor.yy192, *(yymsp[0].minor.yy389));
+ }
+ yymsp[-4].minor.yy243->append(obj);
+ yygotominor.yy243 = yymsp[-4].minor.yy243;
+ delete yymsp[0].minor.yy389;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sortlist");
+ }
+ break;
+ case 167: /* sortlist ::= expr collate sortorder */
+{
+ SqliteOrderBy* obj;
+ if (yymsp[-1].minor.yy319)
+ {
+ SqliteExpr* coll = new SqliteExpr();
+ coll->initCollate(yymsp[-2].minor.yy192, *(yymsp[-1].minor.yy319));
+ delete yymsp[-1].minor.yy319;
+ obj = new SqliteOrderBy(coll, *(yymsp[0].minor.yy389));
+ }
+ else
+ {
+ obj = new SqliteOrderBy(yymsp[-2].minor.yy192, *(yymsp[0].minor.yy389));
+ }
+ yygotominor.yy243 = new ParserOrderByList();
+ yygotominor.yy243->append(obj);
+ delete yymsp[0].minor.yy389;
+ objectForTokens = obj;
+ }
+ break;
+ case 168: /* collate ::= */
+{yygotominor.yy319 = nullptr;}
+ break;
+ case 170: /* sortorder ::= ASC */
+{yygotominor.yy389 = new SqliteSortOrder(SqliteSortOrder::ASC);}
+ break;
+ case 171: /* sortorder ::= DESC */
+{yygotominor.yy389 = new SqliteSortOrder(SqliteSortOrder::DESC);}
+ break;
+ case 172: /* sortorder ::= */
+{yygotominor.yy389 = new SqliteSortOrder(SqliteSortOrder::null);}
+ break;
+ case 173: /* groupby_opt ::= */
+ case 278: /* exprlist ::= */ yytestcase(yyruleno==278);
+{yygotominor.yy231 = new ParserExprList();}
+ break;
+ case 174: /* groupby_opt ::= GROUP BY nexprlist */
+ case 277: /* exprlist ::= nexprlist */ yytestcase(yyruleno==277);
+{yygotominor.yy231 = yymsp[0].minor.yy231;}
+ break;
+ case 175: /* groupby_opt ::= GROUP BY */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy231 = new ParserExprList();
+ }
+ break;
+ case 176: /* having_opt ::= */
+ case 188: /* where_opt ::= */ yytestcase(yyruleno==188);
+ case 274: /* case_else ::= */ yytestcase(yyruleno==274);
+ case 276: /* case_operand ::= */ yytestcase(yyruleno==276);
+ case 334: /* when_clause ::= */ yytestcase(yyruleno==334);
+ case 347: /* key_opt ::= */ yytestcase(yyruleno==347);
+{yygotominor.yy192 = nullptr;}
+ break;
+ case 177: /* having_opt ::= HAVING expr */
+ case 189: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==189);
+ case 266: /* expr ::= exprx */ yytestcase(yyruleno==266);
+ case 273: /* case_else ::= ELSE expr */ yytestcase(yyruleno==273);
+ case 275: /* case_operand ::= exprx */ yytestcase(yyruleno==275);
+ case 335: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==335);
+{yygotominor.yy192 = yymsp[0].minor.yy192;}
+ break;
+ case 178: /* limit_opt ::= */
+{yygotominor.yy324 = nullptr;}
+ break;
+ case 179: /* limit_opt ::= LIMIT signed */
+{
+ yygotominor.yy324 = new SqliteLimit(*(yymsp[0].minor.yy69));
+ delete yymsp[0].minor.yy69;
+ objectForTokens = yygotominor.yy324;
+ }
+ break;
+ case 180: /* limit_opt ::= LIMIT signed OFFSET signed */
+{
+ SqliteExpr* expr1 = new SqliteExpr();
+ expr1->initLiteral(*(yymsp[-2].minor.yy69));
+ expr1->setParent(yygotominor.yy324);
+
+ SqliteExpr* expr2 = new SqliteExpr();
+ expr1->initLiteral(*(yymsp[0].minor.yy69));
+ expr1->setParent(yygotominor.yy324);
+
+ yygotominor.yy324 = new SqliteLimit(expr1, expr2, true);
+
+ TokenPtr limitToken = TokenPtr::create(Token::INTEGER, yymsp[-2].minor.yy69->toString());
+ parserContext->addManagedToken(limitToken);
+ expr1->tokens << limitToken;
+ expr1->tokensMap["term"] << limitToken;
+
+ TokenPtr offsetToken = TokenPtr::create(Token::INTEGER, yymsp[0].minor.yy69->toString());
+ parserContext->addManagedToken(offsetToken);
+ expr2->tokens << offsetToken;
+ expr2->tokensMap["term"] << offsetToken;
+
+ delete yymsp[-2].minor.yy69;
+ delete yymsp[0].minor.yy69;
+ objectForTokens = yygotominor.yy324;
+ }
+ break;
+ case 181: /* limit_opt ::= LIMIT signed COMMA signed */
+{
+ SqliteExpr* expr1 = new SqliteExpr();
+ expr1->initLiteral(*(yymsp[-2].minor.yy69));
+ expr1->setParent(yygotominor.yy324);
+
+ SqliteExpr* expr2 = new SqliteExpr();
+ expr1->initLiteral(*(yymsp[0].minor.yy69));
+ expr1->setParent(yygotominor.yy324);
+
+ yygotominor.yy324 = new SqliteLimit(expr1, expr2, false);
+
+ TokenPtr limitToken = TokenPtr::create(Token::INTEGER, yymsp[-2].minor.yy69->toString());
+ parserContext->addManagedToken(limitToken);
+ expr1->tokens << limitToken;
+ expr1->tokensMap["term"] << limitToken;
+
+ TokenPtr offsetToken = TokenPtr::create(Token::INTEGER, yymsp[0].minor.yy69->toString());
+ parserContext->addManagedToken(offsetToken);
+ expr2->tokens << offsetToken;
+ expr2->tokensMap["term"] << offsetToken;
+
+ delete yymsp[-2].minor.yy69;
+ delete yymsp[0].minor.yy69;
+ objectForTokens = yygotominor.yy324;
+ }
+ break;
+ case 183: /* delete_stmt ::= DELETE FROM fullname where_opt */
+{
+ yygotominor.yy203 = new SqliteDelete(
+ yymsp[-1].minor.yy120->name1,
+ yymsp[-1].minor.yy120->name2,
+ false,
+ yymsp[0].minor.yy192,
+ nullptr
+ );
+ delete yymsp[-1].minor.yy120;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 184: /* delete_stmt ::= DELETE FROM */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ yygotominor.yy203 = q;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 185: /* delete_stmt ::= DELETE FROM nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->database = *(yymsp[-1].minor.yy319);
+ yygotominor.yy203 = q;
+ objectForTokens = yygotominor.yy203;
+ delete yymsp[-1].minor.yy319;
+ }
+ break;
+ case 190: /* where_opt ::= WHERE */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy192 = new SqliteExpr();
+ }
+ break;
+ case 192: /* update_stmt ::= UPDATE orconf fullname SET setlist where_opt */
+{
+ yygotominor.yy203 = new SqliteUpdate(
+ *(yymsp[-4].minor.yy418),
+ yymsp[-3].minor.yy120->name1,
+ yymsp[-3].minor.yy120->name2,
+ false,
+ QString::null,
+ *(yymsp[-1].minor.yy201),
+ yymsp[0].minor.yy192,
+ nullptr
+ );
+ delete yymsp[-4].minor.yy418;
+ delete yymsp[-3].minor.yy120;
+ delete yymsp[-1].minor.yy201;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 193: /* update_stmt ::= UPDATE orconf */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy203 = new SqliteUpdate();
+ objectForTokens = yygotominor.yy203;
+ delete yymsp[0].minor.yy418;
+ }
+ break;
+ case 194: /* update_stmt ::= UPDATE orconf nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->database = *(yymsp[-1].minor.yy319);
+ yygotominor.yy203 = q;
+ objectForTokens = yygotominor.yy203;
+ delete yymsp[-2].minor.yy418;
+ delete yymsp[-1].minor.yy319;
+ }
+ break;
+ case 197: /* setlist ::= setlist COMMA nm EQ expr */
+{
+ yymsp[-4].minor.yy201->append(ParserSetValue(*(yymsp[-2].minor.yy319), yymsp[0].minor.yy192));
+ yygotominor.yy201 = yymsp[-4].minor.yy201;
+ delete yymsp[-2].minor.yy319;
+ DONT_INHERIT_TOKENS("setlist");
+ }
+ break;
+ case 198: /* setlist ::= nm EQ expr */
+{
+ yygotominor.yy201 = new ParserSetValueList();
+ yygotominor.yy201->append(ParserSetValue(*(yymsp[-2].minor.yy319), yymsp[0].minor.yy192));
+ delete yymsp[-2].minor.yy319;
+ }
+ break;
+ case 199: /* setlist ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy201 = new ParserSetValueList();
+ }
+ break;
+ case 200: /* setlist ::= setlist COMMA */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy201 = yymsp[-1].minor.yy201;
+ }
+ break;
+ case 201: /* setlist ::= setlist COMMA ID_COL */
+ case 202: /* setlist ::= ID_COL */ yytestcase(yyruleno==202);
+{ yy_destructor(yypParser,216,&yymsp[-2].minor);
+}
+ break;
+ case 204: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt VALUES LP exprlist RP */
+{
+ yygotominor.yy203 = new SqliteInsert(
+ yymsp[-7].minor.yy344->replace,
+ yymsp[-7].minor.yy344->orConflict,
+ yymsp[-5].minor.yy120->name1,
+ yymsp[-5].minor.yy120->name2,
+ *(yymsp[-4].minor.yy207),
+ *(yymsp[-1].minor.yy231),
+ nullptr
+ );
+ delete yymsp[-5].minor.yy120;
+ delete yymsp[-7].minor.yy344;
+ delete yymsp[-1].minor.yy231;
+ delete yymsp[-4].minor.yy207;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 205: /* insert_stmt ::= insert_cmd INTO fullname inscollist_opt select */
+{
+ yygotominor.yy203 = new SqliteInsert(
+ yymsp[-4].minor.yy344->replace,
+ yymsp[-4].minor.yy344->orConflict,
+ yymsp[-2].minor.yy120->name1,
+ yymsp[-2].minor.yy120->name2,
+ *(yymsp[-1].minor.yy207),
+ yymsp[0].minor.yy153,
+ nullptr
+ );
+ delete yymsp[-2].minor.yy120;
+ delete yymsp[-4].minor.yy344;
+ delete yymsp[-1].minor.yy207;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 206: /* insert_stmt ::= insert_cmd INTO */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = yymsp[-1].minor.yy344->replace;
+ q->onConflict = yymsp[-1].minor.yy344->orConflict;
+ yygotominor.yy203 = q;
+ objectForTokens = yygotominor.yy203;
+ delete yymsp[-1].minor.yy344;
+ }
+ break;
+ case 207: /* insert_stmt ::= insert_cmd INTO nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = yymsp[-3].minor.yy344->replace;
+ q->onConflict = yymsp[-3].minor.yy344->orConflict;
+ q->database = *(yymsp[-1].minor.yy319);
+ yygotominor.yy203 = q;
+ objectForTokens = yygotominor.yy203;
+ delete yymsp[-3].minor.yy344;
+ delete yymsp[-1].minor.yy319;
+ }
+ break;
+ case 208: /* insert_stmt ::= insert_cmd INTO ID_DB|ID_TAB */
+{ yy_destructor(yypParser,218,&yymsp[-2].minor);
+}
+ break;
+ case 209: /* insert_stmt ::= insert_cmd INTO nm DOT ID_TAB */
+{ yy_destructor(yypParser,218,&yymsp[-4].minor);
+ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 210: /* insert_cmd ::= INSERT orconf */
+{
+ yygotominor.yy344 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy418));
+ delete yymsp[0].minor.yy418;
+ }
+ break;
+ case 211: /* insert_cmd ::= REPLACE */
+{yygotominor.yy344 = new ParserStubInsertOrReplace(true);}
+ break;
+ case 212: /* inscollist_opt ::= */
+{yygotominor.yy207 = new ParserStringList();}
+ break;
+ case 213: /* inscollist_opt ::= LP inscollist RP */
+{yygotominor.yy207 = yymsp[-1].minor.yy207;}
+ break;
+ case 214: /* inscollist ::= inscollist COMMA nm */
+{
+ yymsp[-2].minor.yy207->append(*(yymsp[0].minor.yy319));
+ yygotominor.yy207 = yymsp[-2].minor.yy207;
+ delete yymsp[0].minor.yy319;
+ DONT_INHERIT_TOKENS("inscollist");
+ }
+ break;
+ case 215: /* inscollist ::= nm */
+{
+ yygotominor.yy207 = new ParserStringList();
+ yygotominor.yy207->append(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 216: /* inscollist ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy207 = new ParserStringList();
+ }
+ break;
+ case 217: /* inscollist ::= inscollist COMMA ID_COL */
+ case 218: /* inscollist ::= ID_COL */ yytestcase(yyruleno==218);
+{ yy_destructor(yypParser,210,&yymsp[-2].minor);
+}
+ break;
+ case 219: /* exprx ::= NULL */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initNull();
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 220: /* exprx ::= INTEGER */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toLongLong();
+ yygotominor.yy192->initLiteral(val);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 221: /* exprx ::= FLOAT */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ QVariant val = QVariant(yymsp[0].minor.yy0->value).toDouble();
+ yygotominor.yy192->initLiteral(val);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 222: /* exprx ::= STRING */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initLiteral(QVariant(yymsp[0].minor.yy0->value));
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 223: /* exprx ::= LP expr RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initSubExpr(yymsp[-1].minor.yy192);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 224: /* exprx ::= id */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 225: /* exprx ::= JOIN_KW */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 226: /* exprx ::= nm DOT nm */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(*(yymsp[-2].minor.yy319), *(yymsp[0].minor.yy319));
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 227: /* exprx ::= nm DOT nm DOT nm */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(*(yymsp[-4].minor.yy319), *(yymsp[-2].minor.yy319), *(yymsp[0].minor.yy319));
+ delete yymsp[-4].minor.yy319;
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 228: /* exprx ::= VARIABLE */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initBindParam(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 229: /* exprx ::= ID LP exprlist RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initFunction(yymsp[-3].minor.yy0->value, false, *(yymsp[-1].minor.yy231));
+ delete yymsp[-1].minor.yy231;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 230: /* exprx ::= ID LP STAR RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initFunction(yymsp[-3].minor.yy0->value, true);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 231: /* exprx ::= expr AND expr */
+ case 232: /* exprx ::= expr OR expr */ yytestcase(yyruleno==232);
+ case 233: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==233);
+ case 234: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==234);
+ case 235: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==235);
+ case 236: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==236);
+ case 237: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==237);
+ case 238: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==238);
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initBinOp(yymsp[-2].minor.yy192, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy192);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 239: /* exprx ::= expr not_opt likeop expr */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initLike(yymsp[-3].minor.yy192, *(yymsp[-2].minor.yy291), *(yymsp[-1].minor.yy41), yymsp[0].minor.yy192);
+ delete yymsp[-2].minor.yy291;
+ delete yymsp[-1].minor.yy41;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 240: /* exprx ::= expr ISNULL|NOTNULL */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initNull(yymsp[-1].minor.yy192, yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 241: /* exprx ::= expr NOT NULL */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initNull(yymsp[-2].minor.yy192, "NOT NULL");
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 242: /* exprx ::= expr IS not_opt expr */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initIs(yymsp[-3].minor.yy192, *(yymsp[-1].minor.yy291), yymsp[0].minor.yy192);
+ delete yymsp[-1].minor.yy291;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 243: /* exprx ::= NOT expr */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initUnaryOp(yymsp[0].minor.yy192, yymsp[-1].minor.yy0->value);
+ }
+ break;
+ case 244: /* exprx ::= BITNOT expr */
+ case 245: /* exprx ::= MINUS expr */ yytestcase(yyruleno==245);
+ case 246: /* exprx ::= PLUS expr */ yytestcase(yyruleno==246);
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initUnaryOp(yymsp[0].minor.yy192, yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 247: /* exprx ::= expr not_opt BETWEEN expr AND expr */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initBetween(yymsp[-5].minor.yy192, *(yymsp[-4].minor.yy291), yymsp[-2].minor.yy192, yymsp[0].minor.yy192);
+ delete yymsp[-4].minor.yy291;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 248: /* exprx ::= expr not_opt IN LP exprlist RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initIn(yymsp[-5].minor.yy192, *(yymsp[-4].minor.yy291), *(yymsp[-1].minor.yy231));
+ delete yymsp[-4].minor.yy291;
+ delete yymsp[-1].minor.yy231;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 249: /* exprx ::= expr not_opt IN LP select RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initIn(yymsp[-5].minor.yy192, *(yymsp[-4].minor.yy291), yymsp[-1].minor.yy153);
+ delete yymsp[-4].minor.yy291;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 250: /* exprx ::= expr not_opt IN nm dbnm */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initIn(yymsp[-4].minor.yy192, yymsp[-3].minor.yy291, *(yymsp[-1].minor.yy319), *(yymsp[0].minor.yy319));
+ delete yymsp[-3].minor.yy291;
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 251: /* exprx ::= LP select RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initSubSelect(yymsp[-1].minor.yy153);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 252: /* exprx ::= CASE case_operand case_exprlist case_else END */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initCase(yymsp[-3].minor.yy192, *(yymsp[-2].minor.yy231), yymsp[-1].minor.yy192);
+ delete yymsp[-2].minor.yy231;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 253: /* exprx ::= RAISE LP raisetype COMMA nm RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy319));
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 254: /* exprx ::= RAISE LP IGNORE RP */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initRaise(yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy192;
+ }
+ break;
+ case 255: /* exprx ::= nm DOT */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(*(yymsp[-1].minor.yy319), QString::null, QString::null);
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 256: /* exprx ::= nm DOT nm DOT */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ yygotominor.yy192->initId(*(yymsp[-3].minor.yy319), *(yymsp[-1].minor.yy319), QString::null);
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 257: /* exprx ::= expr not_opt BETWEEN expr */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ delete yymsp[-2].minor.yy291;
+ delete yymsp[-3].minor.yy192;
+ delete yymsp[0].minor.yy192;
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 258: /* exprx ::= CASE case_operand case_exprlist case_else */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ delete yymsp[-1].minor.yy231;
+ delete yymsp[-2].minor.yy192;
+ delete yymsp[0].minor.yy192;
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 259: /* exprx ::= expr not_opt IN LP exprlist */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ delete yymsp[-3].minor.yy291;
+ delete yymsp[0].minor.yy231;
+ delete yymsp[-4].minor.yy192;
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 260: /* exprx ::= expr not_opt IN ID_DB */
+{ yy_destructor(yypParser,177,&yymsp[-3].minor);
+}
+ break;
+ case 261: /* exprx ::= expr not_opt IN nm DOT ID_TAB */
+ case 262: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==262);
+{ yy_destructor(yypParser,177,&yymsp[-5].minor);
+ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 264: /* exprx ::= nm DOT nm DOT ID_COL */
+ case 265: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==265);
+{ yy_destructor(yypParser,156,&yymsp[-4].minor);
+ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 267: /* expr ::= */
+{
+ yygotominor.yy192 = new SqliteExpr();
+ objectForTokens = yygotominor.yy192;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 270: /* likeop ::= LIKE|GLOB */
+{yygotominor.yy41 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));}
+ break;
+ case 271: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+{
+ yymsp[-4].minor.yy231->append(yymsp[-2].minor.yy192);
+ yymsp[-4].minor.yy231->append(yymsp[0].minor.yy192);
+ yygotominor.yy231 = yymsp[-4].minor.yy231;
+ }
+ break;
+ case 272: /* case_exprlist ::= WHEN expr THEN expr */
+{
+ yygotominor.yy231 = new ParserExprList();
+ yygotominor.yy231->append(yymsp[-2].minor.yy192);
+ yygotominor.yy231->append(yymsp[0].minor.yy192);
+ }
+ break;
+ case 279: /* nexprlist ::= nexprlist COMMA expr */
+{
+ yymsp[-2].minor.yy231->append(yymsp[0].minor.yy192);
+ yygotominor.yy231 = yymsp[-2].minor.yy231;
+ DONT_INHERIT_TOKENS("nexprlist");
+ }
+ break;
+ case 280: /* nexprlist ::= exprx */
+{
+ yygotominor.yy231 = new ParserExprList();
+ yygotominor.yy231->append(yymsp[0].minor.yy192);
+ }
+ break;
+ case 281: /* cmd ::= CREATE uniqueflag INDEX nm ON nm dbnm LP idxlist RP onconf */
+{
+ yygotominor.yy203 = new SqliteCreateIndex(
+ *(yymsp[-9].minor.yy291),
+ false,
+ *(yymsp[-7].minor.yy319),
+ *(yymsp[-5].minor.yy319),
+ *(yymsp[-4].minor.yy319),
+ *(yymsp[-2].minor.yy63),
+ *(yymsp[0].minor.yy418)
+ );
+ delete yymsp[-9].minor.yy291;
+ delete yymsp[-7].minor.yy319;
+ delete yymsp[-5].minor.yy319;
+ delete yymsp[-4].minor.yy319;
+ delete yymsp[-2].minor.yy63;
+ delete yymsp[0].minor.yy418;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 282: /* cmd ::= CREATE uniqueflag INDEX nm dbnm ON ID_TAB */
+{ yy_destructor(yypParser,156,&yymsp[-3].minor);
+}
+ break;
+ case 287: /* idxlist_opt ::= */
+{yygotominor.yy63 = new ParserIndexedColumnList();}
+ break;
+ case 288: /* idxlist_opt ::= LP idxlist RP */
+{yygotominor.yy63 = yymsp[-1].minor.yy63;}
+ break;
+ case 289: /* idxlist ::= idxlist COMMA idxlist_single */
+{
+ yymsp[-2].minor.yy63->append(yymsp[0].minor.yy428);
+ yygotominor.yy63 = yymsp[-2].minor.yy63;
+ DONT_INHERIT_TOKENS("idxlist");
+ }
+ break;
+ case 290: /* idxlist ::= idxlist_single */
+{
+ yygotominor.yy63 = new ParserIndexedColumnList();
+ yygotominor.yy63->append(yymsp[0].minor.yy428);
+ }
+ break;
+ case 291: /* idxlist_single ::= nm sortorder */
+ case 292: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==292);
+{
+ SqliteIndexedColumn* obj =
+ new SqliteIndexedColumn(
+ *(yymsp[-1].minor.yy319),
+ QString::null,
+ *(yymsp[0].minor.yy389)
+ );
+ yygotominor.yy428 = obj;
+ delete yymsp[0].minor.yy389;
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy428;
+ }
+ break;
+ case 293: /* cmd ::= DROP INDEX fullname */
+{
+ yygotominor.yy203 = new SqliteDropIndex(false, yymsp[0].minor.yy120->name1, yymsp[0].minor.yy120->name2);
+ delete yymsp[0].minor.yy120;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 296: /* cmd ::= COPY orconf nm dbnm FROM nm USING DELIMITERS STRING */
+{
+ yygotominor.yy203 = new SqliteCopy(
+ *(yymsp[-7].minor.yy418),
+ *(yymsp[-6].minor.yy319),
+ *(yymsp[-5].minor.yy319),
+ *(yymsp[-3].minor.yy319),
+ yymsp[0].minor.yy0->value
+ );
+ delete yymsp[-7].minor.yy418;
+ delete yymsp[-6].minor.yy319;
+ delete yymsp[-5].minor.yy319;
+ delete yymsp[-3].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 297: /* cmd ::= COPY orconf nm dbnm FROM nm */
+{
+ yygotominor.yy203 = new SqliteCopy(
+ *(yymsp[-4].minor.yy418),
+ *(yymsp[-3].minor.yy319),
+ *(yymsp[-2].minor.yy319),
+ *(yymsp[0].minor.yy319)
+ );
+ delete yymsp[-4].minor.yy418;
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 298: /* cmd ::= VACUUM */
+{
+ yygotominor.yy203 = new SqliteVacuum();
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 299: /* cmd ::= VACUUM nm */
+{
+ yygotominor.yy203 = new SqliteVacuum(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 300: /* cmd ::= PRAGMA ids */
+{
+ yygotominor.yy203 = new SqlitePragma(*(yymsp[0].minor.yy319), QString::null);
+ delete yymsp[0].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 301: /* cmd ::= PRAGMA nm EQ nmnum */
+ case 303: /* cmd ::= PRAGMA nm EQ minus_num */ yytestcase(yyruleno==303);
+{
+ yygotominor.yy203 = new SqlitePragma(*(yymsp[-2].minor.yy319), QString::null, *(yymsp[0].minor.yy69), true);
+ delete yymsp[-2].minor.yy319;
+ delete yymsp[0].minor.yy69;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 302: /* cmd ::= PRAGMA nm LP nmnum RP */
+ case 304: /* cmd ::= PRAGMA nm LP minus_num RP */ yytestcase(yyruleno==304);
+{
+ yygotominor.yy203 = new SqlitePragma(*(yymsp[-3].minor.yy319), QString::null, *(yymsp[-1].minor.yy69), false);
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-1].minor.yy69;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 308: /* nmnum ::= nm */
+{
+ yygotominor.yy69 = new QVariant(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ }
+ break;
+ case 309: /* nmnum ::= ON */
+ case 310: /* nmnum ::= DELETE */ yytestcase(yyruleno==310);
+ case 311: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==311);
+{yygotominor.yy69 = new QVariant(yymsp[0].minor.yy0->value);}
+ break;
+ case 314: /* minus_num ::= MINUS number */
+{
+ if (yymsp[0].minor.yy69->type() == QVariant::Double)
+ *(yymsp[0].minor.yy69) = -(yymsp[0].minor.yy69->toDouble());
+ else if (yymsp[0].minor.yy69->type() == QVariant::LongLong)
+ *(yymsp[0].minor.yy69) = -(yymsp[0].minor.yy69->toLongLong());
+ else
+ Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong.");
+
+ yygotominor.yy69 = yymsp[0].minor.yy69;
+ }
+ break;
+ case 315: /* number ::= INTEGER */
+{yygotominor.yy69 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toLongLong());}
+ break;
+ case 316: /* number ::= FLOAT */
+{yygotominor.yy69 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());}
+ break;
+ case 317: /* cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause BEGIN trigger_cmd_list END */
+{
+ yygotominor.yy203 = new SqliteCreateTrigger(
+ *(yymsp[-12].minor.yy226),
+ false,
+ *(yymsp[-10].minor.yy319),
+ *(yymsp[-6].minor.yy319),
+ *(yymsp[-5].minor.yy319),
+ *(yymsp[-9].minor.yy372),
+ yymsp[-8].minor.yy151,
+ *(yymsp[-4].minor.yy83),
+ yymsp[-3].minor.yy192,
+ *(yymsp[-1].minor.yy270),
+ 2
+ );
+ delete yymsp[-12].minor.yy226;
+ delete yymsp[-9].minor.yy372;
+ delete yymsp[-4].minor.yy83;
+ delete yymsp[-6].minor.yy319;
+ delete yymsp[-10].minor.yy319;
+ delete yymsp[-5].minor.yy319;
+ delete yymsp[-1].minor.yy270;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 318: /* cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause */
+{
+ QList<SqliteQuery *> CL;
+
+ yygotominor.yy203 = new SqliteCreateTrigger(
+ *(yymsp[-9].minor.yy226),
+ false,
+ *(yymsp[-7].minor.yy319),
+ *(yymsp[-3].minor.yy319),
+ *(yymsp[-2].minor.yy319),
+ *(yymsp[-6].minor.yy372),
+ yymsp[-5].minor.yy151,
+ *(yymsp[-1].minor.yy83),
+ yymsp[0].minor.yy192,
+ CL,
+ 2
+ );
+ delete yymsp[-9].minor.yy226;
+ delete yymsp[-6].minor.yy372;
+ delete yymsp[-1].minor.yy83;
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-7].minor.yy319;
+ delete yymsp[-2].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 319: /* cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause BEGIN trigger_cmd_list */
+{
+ yygotominor.yy203 = new SqliteCreateTrigger(
+ *(yymsp[-11].minor.yy226),
+ false,
+ *(yymsp[-9].minor.yy319),
+ *(yymsp[-5].minor.yy319),
+ *(yymsp[-4].minor.yy319),
+ *(yymsp[-8].minor.yy372),
+ yymsp[-7].minor.yy151,
+ *(yymsp[-3].minor.yy83),
+ yymsp[-2].minor.yy192,
+ *(yymsp[0].minor.yy270),
+ 2
+ );
+ delete yymsp[-11].minor.yy226;
+ delete yymsp[-8].minor.yy372;
+ delete yymsp[-3].minor.yy83;
+ delete yymsp[-5].minor.yy319;
+ delete yymsp[-9].minor.yy319;
+ delete yymsp[-4].minor.yy319;
+ delete yymsp[0].minor.yy270;
+ objectForTokens = yygotominor.yy203;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 320: /* cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON ID_TAB|ID_DB */
+{ yy_destructor(yypParser,157,&yymsp[-6].minor);
+ yy_destructor(yypParser,156,&yymsp[-4].minor);
+ yy_destructor(yypParser,232,&yymsp[-3].minor);
+ yy_destructor(yypParser,233,&yymsp[-2].minor);
+}
+ break;
+ case 321: /* cmd ::= CREATE temp TRIGGER nm trigger_time trigger_event ON nm DOT ID_TAB */
+{ yy_destructor(yypParser,157,&yymsp[-8].minor);
+ yy_destructor(yypParser,156,&yymsp[-6].minor);
+ yy_destructor(yypParser,232,&yymsp[-5].minor);
+ yy_destructor(yypParser,233,&yymsp[-4].minor);
+ yy_destructor(yypParser,156,&yymsp[-2].minor);
+}
+ break;
+ case 323: /* trigger_time ::= BEFORE */
+{yygotominor.yy372 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);}
+ break;
+ case 324: /* trigger_time ::= AFTER */
+{yygotominor.yy372 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);}
+ break;
+ case 325: /* trigger_time ::= INSTEAD OF */
+{yygotominor.yy372 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);}
+ break;
+ case 326: /* trigger_time ::= */
+{yygotominor.yy372 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);}
+ break;
+ case 327: /* trigger_event ::= DELETE */
+{
+ yygotominor.yy151 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE);
+ objectForTokens = yygotominor.yy151;
+ }
+ break;
+ case 328: /* trigger_event ::= INSERT */
+{
+ yygotominor.yy151 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT);
+ objectForTokens = yygotominor.yy151;
+ }
+ break;
+ case 329: /* trigger_event ::= UPDATE */
+{
+ yygotominor.yy151 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE);
+ objectForTokens = yygotominor.yy151;
+ }
+ break;
+ case 330: /* trigger_event ::= UPDATE OF inscollist */
+{
+ yygotominor.yy151 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy207));
+ delete yymsp[0].minor.yy207;
+ objectForTokens = yygotominor.yy151;
+ }
+ break;
+ case 331: /* foreach_clause ::= */
+{yygotominor.yy83 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);}
+ break;
+ case 332: /* foreach_clause ::= FOR EACH ROW */
+{yygotominor.yy83 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);}
+ break;
+ case 333: /* foreach_clause ::= FOR EACH STATEMENT */
+{yygotominor.yy83 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_STATEMENT);}
+ break;
+ case 336: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+{
+ yymsp[-2].minor.yy270->append(yymsp[-1].minor.yy203);
+ yygotominor.yy270 = yymsp[-2].minor.yy270;
+ DONT_INHERIT_TOKENS("trigger_cmd_list");
+ }
+ break;
+ case 337: /* trigger_cmd_list ::= trigger_cmd SEMI */
+{
+ yygotominor.yy270 = new ParserQueryList();
+ yygotominor.yy270->append(yymsp[-1].minor.yy203);
+ }
+ break;
+ case 342: /* raisetype ::= ROLLBACK|ABORT|FAIL */
+{yygotominor.yy0 = yymsp[0].minor.yy0;}
+ break;
+ case 343: /* cmd ::= DROP TRIGGER fullname */
+{
+ yygotominor.yy203 = new SqliteDropTrigger(false, yymsp[0].minor.yy120->name1, yymsp[0].minor.yy120->name2);
+ delete yymsp[0].minor.yy120;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 346: /* cmd ::= ATTACH database_kw_opt ids AS ids key_opt */
+{
+ SqliteExpr* e1 = new SqliteExpr();
+ SqliteExpr* e2 = new SqliteExpr();
+ e1->initLiteral(*(yymsp[-3].minor.yy319));
+ e2->initLiteral(*(yymsp[-1].minor.yy319));
+ yygotominor.yy203 = new SqliteAttach(*(yymsp[-4].minor.yy291), e1, e2, yymsp[0].minor.yy192);
+ delete yymsp[-4].minor.yy291;
+ delete yymsp[-3].minor.yy319;
+ delete yymsp[-1].minor.yy319;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ case 348: /* key_opt ::= USING ids */
+{
+ SqliteExpr* e = new SqliteExpr();
+ e->initLiteral(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ yygotominor.yy192 = e;
+ }
+ break;
+ case 351: /* cmd ::= DETACH database_kw_opt nm */
+{
+ SqliteExpr* e = new SqliteExpr();
+ e->initLiteral(*(yymsp[0].minor.yy319));
+ delete yymsp[0].minor.yy319;
+ yygotominor.yy203 = new SqliteDetach(*(yymsp[-1].minor.yy291), e);
+ delete yymsp[-1].minor.yy291;
+ objectForTokens = yygotominor.yy203;
+ }
+ break;
+ default:
+ /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
+ break;
+ };
+ }
+ assert( yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0])) );
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+
+ // Store tokens for the rule in parser context
+ QList<Token*> allTokens;
+ QList<Token*> allTokensWithAllInherited;
+ QString keyForTokensMap;
+ int tokensMapKeyCnt;
+ if (parserContext->setupTokens)
+ {
+ if (objectForTokens)
+ {
+ // In case this is a list with recurrent references we need
+ // to clear tokens before adding the new and extended list.
+ objectForTokens->tokens.clear();
+ }
+
+ QList<Token*> tokens;
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ tokens.clear();
+ const char* fieldName = yyTokenName[yypParser->yystack[i].major];
+ if (parserContext->isManagedToken(yypParser->yystack[i].minor.yy0))
+ tokens += yypParser->yystack[i].minor.yy0;
+
+ tokens += *(yypParser->yystack[i].tokens);
+
+ if (!noTokenInheritanceFields.contains(fieldName))
+ {
+ if (objectForTokens)
+ {
+ keyForTokensMap = fieldName;
+ tokensMapKeyCnt = 2;
+ while (objectForTokens->tokensMap.contains(keyForTokensMap))
+ keyForTokensMap = fieldName + QString::number(tokensMapKeyCnt++);
+
+ objectForTokens->tokensMap[keyForTokensMap] = parserContext->getTokenPtrList(tokens);
+ }
+
+ allTokens += tokens;
+ }
+ else
+ {
+ // If field is mentioned only once, then only one occurance of it will be ignored.
+ // Second one should be inherited. See "anylist" definition for explanation why.
+ noTokenInheritanceFields.removeOne(fieldName);
+ }
+ allTokensWithAllInherited += tokens;
+ }
+ if (objectForTokens)
+ {
+ objectForTokens->tokens += parserContext->getTokenPtrList(allTokens);
+ }
+ }
+
+ // Clear token lists
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ delete yypParser->yystack[i].tokens;
+ yypParser->yystack[i].tokens = nullptr;
+ }
+
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+ if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+ /* If we are not debugging and the reduce action popped at least
+ ** one element off the stack, then we can push the new element back
+ ** onto the stack here, and skip the stack overflow test in yy_shift().
+ ** That gives a significant speed improvement. */
+ if( yysize ){
+ yypParser->yyidx++;
+ yymsp -= yysize-1;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yymsp->minor = yygotominor;
+ if (parserContext->setupTokens)
+ *(yypParser->yystack[yypParser->yyidx].tokens) = allTokens;
+ }else
+#endif
+ {
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ if (parserContext->setupTokens)
+ {
+ QList<Token*>* tokensPtr = yypParser->yystack[yypParser->yyidx].tokens;
+ *tokensPtr = allTokensWithAllInherited + *tokensPtr;
+ }
+ }
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ sqlite2_parseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+ sqlite2_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ sqlite2_parseARG_FETCH;
+#define TOKEN (yyminor.yy0)
+
+ UNUSED_PARAMETER(yymajor);
+ parserContext->error(TOKEN, QObject::tr("Syntax error"));
+ sqlite2_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ sqlite2_parseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+ sqlite2_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "sqlite2_parseAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void sqlite2_parse(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ sqlite2_parseTOKENTYPE yyminor /* The value for the token */
+ sqlite2_parseARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ int yyendofinput; /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
+ yyminorunion = yyzerominor;
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ yypParser->yystack[0].tokens = new QList<Token*>();
+ }
+ yyminorunion.yy0 = yyminor;
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ yyendofinput = (yymajor==0);
+#endif
+ sqlite2_parseARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s [%s] (lemon type: %s)\n",
+ yyTracePrompt,
+ yyminor->value.toLatin1().data(),
+ yyminor->typeString().toLatin1().data(),
+ yyTokenName[yymajor]); }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ yymajor = YYNOCODE;
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
+ int yymx;
+#endif
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_reduce_action(
+ yypParser->yystack[yypParser->yyidx].stateno,
+ YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+ /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+ ** do any kind of error recovery. Instead, simply invoke the syntax
+ ** error routine and continue going as if nothing had happened.
+ **
+ ** Applications can set this macro (for example inside %include) if
+ ** they intend to abandon the parse upon the first syntax error seen.
+ */
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.h b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.h
new file mode 100644
index 0000000..058d397
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.h
@@ -0,0 +1,146 @@
+#define TK2_ILLEGAL 1
+#define TK2_COMMENT 2
+#define TK2_SPACE 3
+#define TK2_ID 4
+#define TK2_ABORT 5
+#define TK2_AFTER 6
+#define TK2_ASC 7
+#define TK2_ATTACH 8
+#define TK2_BEFORE 9
+#define TK2_BEGIN 10
+#define TK2_CASCADE 11
+#define TK2_CLUSTER 12
+#define TK2_CONFLICT 13
+#define TK2_COPY 14
+#define TK2_DATABASE 15
+#define TK2_DEFERRED 16
+#define TK2_DELIMITERS 17
+#define TK2_DESC 18
+#define TK2_DETACH 19
+#define TK2_EACH 20
+#define TK2_END 21
+#define TK2_EXPLAIN 22
+#define TK2_FAIL 23
+#define TK2_FOR 24
+#define TK2_GLOB 25
+#define TK2_IGNORE 26
+#define TK2_IMMEDIATE 27
+#define TK2_INITIALLY 28
+#define TK2_INSTEAD 29
+#define TK2_LIKE 30
+#define TK2_MATCH 31
+#define TK2_KEY 32
+#define TK2_OF 33
+#define TK2_OFFSET 34
+#define TK2_PRAGMA 35
+#define TK2_RAISE 36
+#define TK2_REPLACE 37
+#define TK2_RESTRICT 38
+#define TK2_ROW 39
+#define TK2_STATEMENT 40
+#define TK2_TEMP 41
+#define TK2_TRIGGER 42
+#define TK2_VACUUM 43
+#define TK2_VIEW 44
+#define TK2_OR 45
+#define TK2_AND 46
+#define TK2_NOT 47
+#define TK2_EQ 48
+#define TK2_NE 49
+#define TK2_ISNULL 50
+#define TK2_NOTNULL 51
+#define TK2_IS 52
+#define TK2_BETWEEN 53
+#define TK2_IN 54
+#define TK2_GT 55
+#define TK2_GE 56
+#define TK2_LT 57
+#define TK2_LE 58
+#define TK2_BITAND 59
+#define TK2_BITOR 60
+#define TK2_LSHIFT 61
+#define TK2_RSHIFT 62
+#define TK2_PLUS 63
+#define TK2_MINUS 64
+#define TK2_STAR 65
+#define TK2_SLASH 66
+#define TK2_REM 67
+#define TK2_CONCAT 68
+#define TK2_UMINUS 69
+#define TK2_UPLUS 70
+#define TK2_BITNOT 71
+#define TK2_SEMI 72
+#define TK2_TRANSACTION 73
+#define TK2_ID_TRANS 74
+#define TK2_COMMIT 75
+#define TK2_ROLLBACK 76
+#define TK2_CREATE 77
+#define TK2_TABLE 78
+#define TK2_LP 79
+#define TK2_RP 80
+#define TK2_AS 81
+#define TK2_DOT 82
+#define TK2_ID_TAB_NEW 83
+#define TK2_ID_DB 84
+#define TK2_COMMA 85
+#define TK2_ID_COL_NEW 86
+#define TK2_STRING 87
+#define TK2_JOIN_KW 88
+#define TK2_ID_COL_TYPE 89
+#define TK2_DEFAULT 90
+#define TK2_INTEGER 91
+#define TK2_FLOAT 92
+#define TK2_NULL 93
+#define TK2_CONSTRAINT 94
+#define TK2_PRIMARY 95
+#define TK2_UNIQUE 96
+#define TK2_CHECK 97
+#define TK2_REFERENCES 98
+#define TK2_COLLATE 99
+#define TK2_ON 100
+#define TK2_INSERT 101
+#define TK2_DELETE 102
+#define TK2_UPDATE 103
+#define TK2_ID_FK_MATCH 104
+#define TK2_SET 105
+#define TK2_DEFERRABLE 106
+#define TK2_FOREIGN 107
+#define TK2_ID_CONSTR 108
+#define TK2_ID_TAB 109
+#define TK2_DROP 110
+#define TK2_ID_VIEW_NEW 111
+#define TK2_ID_VIEW 112
+#define TK2_UNION 113
+#define TK2_ALL 114
+#define TK2_EXCEPT 115
+#define TK2_INTERSECT 116
+#define TK2_SELECT 117
+#define TK2_DISTINCT 118
+#define TK2_ID_ALIAS 119
+#define TK2_FROM 120
+#define TK2_USING 121
+#define TK2_JOIN 122
+#define TK2_ID_JOIN_OPTS 123
+#define TK2_ORDER 124
+#define TK2_BY 125
+#define TK2_GROUP 126
+#define TK2_HAVING 127
+#define TK2_LIMIT 128
+#define TK2_WHERE 129
+#define TK2_ID_COL 130
+#define TK2_INTO 131
+#define TK2_VALUES 132
+#define TK2_VARIABLE 133
+#define TK2_LIKE_KW 134
+#define TK2_CASE 135
+#define TK2_ID_FN 136
+#define TK2_ID_ERR_MSG 137
+#define TK2_WHEN 138
+#define TK2_THEN 139
+#define TK2_ELSE 140
+#define TK2_INDEX 141
+#define TK2_ID_IDX_NEW 142
+#define TK2_ID_IDX 143
+#define TK2_ID_PRAGMA 144
+#define TK2_ID_TRIG_NEW 145
+#define TK2_ID_TRIG 146
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y
new file mode 100644
index 0000000..e44e9b8
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite2_parse.y
@@ -0,0 +1,2068 @@
+%token_prefix TK2_
+%token_type {Token*}
+%default_type {Token*}
+%extra_argument {ParserContext* parserContext}
+%name sqlite2_parse
+
+%syntax_error {
+ UNUSED_PARAMETER(yymajor);
+ parserContext->error(TOKEN, QObject::tr("Syntax error"));
+}
+
+%stack_overflow {
+ UNUSED_PARAMETER(yypMinor);
+ parserContext->error(QObject::tr("Parser stack overflow"));
+}
+
+%include {
+#include "token.h"
+#include "parsercontext.h"
+#include "parser/ast/sqlitealtertable.h"
+#include "parser/ast/sqliteanalyze.h"
+#include "parser/ast/sqliteattach.h"
+#include "parser/ast/sqlitebegintrans.h"
+#include "parser/ast/sqlitecommittrans.h"
+#include "parser/ast/sqlitecopy.h"
+#include "parser/ast/sqlitecreateindex.h"
+#include "parser/ast/sqlitecreatetable.h"
+#include "parser/ast/sqlitecreatetrigger.h"
+#include "parser/ast/sqlitecreateview.h"
+#include "parser/ast/sqlitecreatevirtualtable.h"
+#include "parser/ast/sqlitedelete.h"
+#include "parser/ast/sqlitedetach.h"
+#include "parser/ast/sqlitedropindex.h"
+#include "parser/ast/sqlitedroptable.h"
+#include "parser/ast/sqlitedroptrigger.h"
+#include "parser/ast/sqlitedropview.h"
+#include "parser/ast/sqliteemptyquery.h"
+#include "parser/ast/sqliteinsert.h"
+#include "parser/ast/sqlitepragma.h"
+#include "parser/ast/sqlitereindex.h"
+#include "parser/ast/sqliterelease.h"
+#include "parser/ast/sqliterollback.h"
+#include "parser/ast/sqlitesavepoint.h"
+#include "parser/ast/sqliteselect.h"
+#include "parser/ast/sqliteupdate.h"
+#include "parser/ast/sqlitevacuum.h"
+#include "parser/ast/sqliteexpr.h"
+#include "parser/ast/sqlitecolumntype.h"
+#include "parser/ast/sqliteconflictalgo.h"
+#include "parser/ast/sqlitesortorder.h"
+#include "parser/ast/sqliteindexedcolumn.h"
+#include "parser/ast/sqliteforeignkey.h"
+#include "parser_helper_stubs.h"
+#include "common/utils_sql.h"
+#include <QObject>
+#include <QDebug>
+
+#define assert(X) Q_ASSERT(X)
+#define UNUSED_PARAMETER(X) (void)(X)
+#define DONT_INHERIT_TOKENS(X) noTokenInheritanceFields << X
+}
+
+// These are extra tokens used by the lexer but never seen by the
+// parser. We put them in a rule so that the parser generator will
+// add them to the parse.h output file.
+
+%nonassoc ILLEGAL COMMENT SPACE.
+
+// The following directive causes tokens ABORT, AFTER, ASC, etc. to
+// fallback to ID if they will not parse as their original value.
+// This obviates the need for the "id" nonterminal.
+
+%fallback ID
+ ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CLUSTER CONFLICT
+ COPY DATABASE DEFERRED DELIMITERS DESC DETACH EACH END EXPLAIN FAIL FOR
+ GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
+ OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
+ TEMP TRIGGER VACUUM VIEW.
+
+// Define operator precedence early so that this is the first occurance
+// of the operator tokens in the grammer. Keeping the operators together
+// causes them to be assigned integer values that are close together,
+// which keeps parser tables smaller.
+
+%left OR.
+%left AND.
+%right NOT.
+%left EQ NE ISNULL NOTNULL IS LIKE GLOB BETWEEN IN.
+%left GT GE LT LE.
+%left BITAND BITOR LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left STAR SLASH REM.
+%left CONCAT.
+%right UMINUS UPLUS BITNOT.
+
+// Input is a single SQL command
+%type cmd {SqliteQuery*}
+%destructor cmd {delete $$;}
+
+input ::= cmdlist.
+
+cmdlist ::= cmdlist ecmd(C). {parserContext->addQuery(C); DONT_INHERIT_TOKENS("cmdlist");}
+cmdlist ::= ecmd(C). {parserContext->addQuery(C);}
+
+%type ecmd {SqliteQuery*}
+%destructor ecmd {delete $$;}
+ecmd(X) ::= SEMI. {X = new SqliteEmptyQuery();}
+ecmd(X) ::= explain(E) cmdx(C) SEMI. {
+ X = C;
+ X->explain = E->explain;
+ X->queryPlan = E->queryPlan;
+ delete E;
+ objectForTokens = X;
+ }
+
+%type explain {ParserStubExplain*}
+%destructor explain {delete $$;}
+explain(X) ::= . {X = new ParserStubExplain(false, false);}
+explain(X) ::= EXPLAIN. {X = new ParserStubExplain(true, false);}
+
+%type cmdx {SqliteQuery*}
+%destructor cmdx {delete $$;}
+cmdx(X) ::= cmd(C). {X = C;}
+
+///////////////////// Begin and end transactions. ////////////////////////////
+
+cmd(X) ::= BEGIN trans_opt(TO) onconf(C). {
+ X = new SqliteBeginTrans(
+ TO->transactionKw,
+ TO->name,
+ *(C)
+ );
+ delete TO;
+ delete C;
+ objectForTokens = X;
+ }
+
+%type trans_opt {ParserStubTransDetails*}
+%destructor trans_opt {delete $$;}
+trans_opt(X) ::= . {X = new ParserStubTransDetails();}
+trans_opt(X) ::= TRANSACTION. {
+ X = new ParserStubTransDetails();
+ X->transactionKw = true;
+ }
+trans_opt(X) ::= TRANSACTION nm(N). {
+ X = new ParserStubTransDetails();
+ X->transactionKw = true;
+ X->name = *(N);
+ delete N;
+ }
+trans_opt ::= TRANSACTION ID_TRANS. {}
+
+cmd(X) ::= COMMIT trans_opt(T). {
+ X = new SqliteCommitTrans(
+ T->transactionKw,
+ T->name,
+ false
+ );
+ delete T;
+ objectForTokens = X;
+ }
+cmd(X) ::= END trans_opt(T). {
+ X = new SqliteCommitTrans(
+ T->transactionKw,
+ T->name,
+ true
+ );
+ delete T;
+ objectForTokens = X;
+ }
+cmd(X) ::= ROLLBACK trans_opt(T). {
+ X = new SqliteRollback(
+ T->transactionKw,
+ T->name
+ );
+ delete T;
+ objectForTokens = X;
+ }
+
+///////////////////// The CREATE TABLE statement ////////////////////////////
+
+cmd(X) ::= CREATE temp(T) TABLE
+ fullname(N)
+ LP columnlist(CL)
+ conslist_opt(CS) RP. {
+ X = new SqliteCreateTable(
+ *(T),
+ false,
+ N->name1,
+ N->name2,
+ *(CL),
+ *(CS)
+ );
+ delete T;
+ delete CL;
+ delete CS;
+ delete N;
+ objectForTokens = X;
+ }
+cmd(X) ::= CREATE temp(T) TABLE
+ fullname(N)
+ AS select(S). {
+ X = new SqliteCreateTable(
+ *(T),
+ false,
+ N->name1,
+ N->name2,
+ S
+ );
+ delete T;
+ delete N;
+ objectForTokens = X;
+ }
+cmd ::= CREATE temp TABLE
+ nm DOT ID_TAB_NEW. {}
+cmd ::= CREATE temp TABLE
+ ID_DB|ID_TAB_NEW. {}
+
+%type temp {int*}
+%destructor temp {delete $$;}
+temp(X) ::= TEMP(T). {X = new int( (T->value.length() > 4) ? 2 : 1 );}
+temp(X) ::= . {X = new int(0);}
+
+%type columnlist {ParserCreateTableColumnList*}
+%destructor columnlist {delete $$;}
+columnlist(X) ::= columnlist(L)
+ COMMA column(C). {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("columnlist");
+ }
+columnlist(X) ::= column(C). {
+ X = new ParserCreateTableColumnList();
+ X->append(C);
+ }
+
+%type column {SqliteCreateTable::Column*}
+%destructor column {delete $$;}
+column(X) ::= columnid(C) type(T)
+ carglist(L). {
+ X = new SqliteCreateTable::Column(*(C), T, *(L));
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+
+%type columnid {QString*}
+%destructor columnid {delete $$;}
+columnid(X) ::= nm(N). {X = N;}
+columnid ::= ID_COL_NEW. {}
+
+// An IDENTIFIER can be a generic identifier, or one of several
+// keywords. Any non-standard keyword can also be an identifier.
+
+%type id {QString*}
+%destructor id {delete $$;}
+id(X) ::= ID(T). {
+ X = new QString(
+ stripObjName(
+ T->value,
+ parserContext->dialect
+ )
+ );
+ }
+
+// And "ids" is an identifer-or-string.
+
+%type ids {QString*}
+%destructor ids {delete $$;}
+ids(X) ::= ID|STRING(T). {X = new QString(T->value);}
+
+// The name of a column or table can be any of the following:
+
+%type nm {QString*}
+%destructor nm {delete $$;}
+nm(X) ::= id(N). {X = N;}
+nm(X) ::= STRING(N). {X = new QString(stripString(N->value));}
+nm(X) ::= JOIN_KW(N). {X = new QString(N->value);}
+
+%type type {SqliteColumnType*}
+%destructor type {delete $$;}
+type(X) ::= . {X = nullptr;}
+type(X) ::= typetoken(T). {X = T;}
+
+%type typetoken {SqliteColumnType*}
+%destructor typetoken {delete $$;}
+typetoken(X) ::= typename(N). {
+ X = new SqliteColumnType(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+typetoken(X) ::= typename(N)
+ LP signed(P) RP. {
+ X = new SqliteColumnType(*(N), *(P));
+ delete N;
+ delete P;
+ objectForTokens = X;
+ }
+typetoken(X) ::= typename(N) LP signed(P)
+ COMMA signed(S) RP. {
+ X = new SqliteColumnType(*(N), *(P), *(S));
+ delete N;
+ delete P;
+ delete S;
+ objectForTokens = X;
+ }
+
+%type typename {QString*}
+%destructor typename {delete $$;}
+typename(X) ::= ids(I). {X = I;}
+typename(X) ::= typename(T) ids(I). {
+ T->append(" " + *(I));
+ delete I;
+ X = T;
+ }
+typename ::= ID_COL_TYPE. {}
+
+%type signed {QVariant*}
+%destructor signed {delete $$;}
+signed(X) ::= plus_num(N). {X = N;}
+signed(X) ::= minus_num(N). {X = N;}
+
+%type carglist {ParserCreateTableColumnConstraintList*}
+%destructor carglist {delete $$;}
+carglist(X) ::= carglist(L) ccons(C). {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+carglist(X) ::= carglist(L) ccons_nm(N)
+ ccons(C). {
+ L->append(N);
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+carglist(X) ::= carglist(L) carg(C). {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+carglist(X) ::= . {X = new ParserCreateTableColumnConstraintList();}
+
+%type carg {SqliteCreateTable::Column::Constraint*}
+%destructor carg {delete $$;}
+carg(X) ::= DEFAULT STRING(S). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefId(stripObjName(
+ S->value,
+ parserContext->dialect
+ ));
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT ID(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefId(stripObjName(
+ I->value,
+ parserContext->dialect
+ ));
+ objectForTokens = X;
+
+ }
+carg(X) ::= DEFAULT INTEGER(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(I->value).toLongLong();
+ X->initDefTerm(val, false);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT PLUS INTEGER(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(I->value).toLongLong();
+ X->initDefTerm(val, false);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT MINUS INTEGER(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(I->value).toLongLong();
+ X->initDefTerm(val, true);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT FLOAT(F). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(F->value).toDouble();
+ X->initDefTerm(val, false);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT PLUS FLOAT(F). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(F->value).toDouble();
+ X->initDefTerm(val, false);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT MINUS FLOAT(F). {
+ X = new SqliteCreateTable::Column::Constraint();
+ QVariant val = QVariant(F->value).toDouble();
+ X->initDefTerm(val, true);
+ objectForTokens = X;
+ }
+carg(X) ::= DEFAULT NULL. {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefTerm(QVariant(), false);
+ objectForTokens = X;
+ }
+
+// In addition to the type name, we also care about the primary key and
+// UNIQUE constraints.
+
+%type ccons_nm {SqliteCreateTable::Column::Constraint*}
+%destructor ccons_nm {delete $$;}
+ccons_nm(X) ::= CONSTRAINT nm(N). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefNameOnly(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+
+%type ccons {SqliteCreateTable::Column::Constraint*}
+%destructor ccons {delete $$;}
+ccons(X) ::= NULL onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initNull(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= NOT NULL onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initNotNull(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= PRIMARY KEY sortorder(O)
+ onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initPk(*(O), *(C), false);
+ delete O;
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= UNIQUE onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initUnique(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= CHECK LP expr(E) RP onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initCheck(E, *(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= REFERENCES nm(N)
+ idxlist_opt(I) refargs(A). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initFk(*(N), *(I), *(A));
+ delete N;
+ delete A;
+ delete I;
+ objectForTokens = X;
+ }
+ccons(X) ::= defer_subclause(D). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefer(D->initially, D->deferrable);
+ delete D;
+ objectForTokens = X;
+ }
+ccons(X) ::= COLLATE id(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initColl(*(I));
+ delete I;
+ objectForTokens = X;
+ }
+ccons(X) ::= CHECK LP RP. {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initCheck();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+// The next group of rules parses the arguments to a REFERENCES clause
+// that determine if the referential integrity checking is deferred or
+// or immediate and which determine what action to take if a ref-integ
+// check fails.
+
+%type refargs {ParserFkConditionList*}
+%destructor refargs {delete $$;}
+refargs(X) ::= . {X = new ParserFkConditionList();}
+refargs(X) ::= refargs(L) refarg(A). {
+ L->append(A);
+ X = L;
+ DONT_INHERIT_TOKENS("refargs");
+ }
+
+%type refarg {SqliteForeignKey::Condition*}
+%destructor refarg {delete $$;}
+refarg(X) ::= MATCH nm(N). {
+ X = new SqliteForeignKey::Condition(*(N));
+ delete N;
+ }
+refarg(X) ::= ON INSERT refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(R)); delete R;}
+refarg(X) ::= ON DELETE refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(R)); delete R;}
+refarg(X) ::= ON UPDATE refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(R)); delete R;}
+refarg ::= MATCH ID_FK_MATCH. {}
+
+%type refact {SqliteForeignKey::Condition::Reaction*}
+%destructor refact {delete $$;}
+refact(X) ::= SET NULL. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);}
+refact(X) ::= SET DEFAULT. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);}
+refact(X) ::= CASCADE. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);}
+refact(X) ::= RESTRICT. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);}
+
+%type defer_subclause {ParserDeferSubClause*}
+%destructor defer_subclause {delete $$;}
+defer_subclause(X) ::= NOT DEFERRABLE
+ init_deferred_pred_opt(I). {
+ X = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(I));
+ delete I;
+ }
+defer_subclause(X) ::= DEFERRABLE
+ init_deferred_pred_opt(I). {
+ X = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(I));
+ delete I;
+ }
+
+%type init_deferred_pred_opt {SqliteInitially*}
+%destructor init_deferred_pred_opt {delete $$;}
+init_deferred_pred_opt(X) ::= . {X = new SqliteInitially(SqliteInitially::null);}
+init_deferred_pred_opt(X) ::= INITIALLY
+ DEFERRED. {X = new SqliteInitially(SqliteInitially::DEFERRED);}
+init_deferred_pred_opt(X) ::= INITIALLY
+ IMMEDIATE. {X = new SqliteInitially(SqliteInitially::IMMEDIATE);}
+
+
+%type conslist_opt {ParserCreateTableConstraintList*}
+%destructor conslist_opt {delete $$;}
+conslist_opt(X) ::= . {X = new ParserCreateTableConstraintList();}
+conslist_opt(X) ::= COMMA conslist(L). {X = L;}
+
+%type conslist {ParserCreateTableConstraintList*}
+%destructor conslist {delete $$;}
+conslist(X) ::= conslist(L) tconscomma(CM)
+ tcons(C). {
+ C->afterComma = *(CM);
+ L->append(C);
+ X = L;
+ delete CM;
+ DONT_INHERIT_TOKENS("conslist");
+ }
+conslist(X) ::= tcons(C). {
+ X = new ParserCreateTableConstraintList();
+ X->append(C);
+ }
+
+%type tconscomma {bool*}
+%destructor tconscomma {delete $$;}
+tconscomma(X) ::= COMMA. {X = new bool(true);}
+tconscomma(X) ::= . {X = new bool(false);}
+
+%type tcons {SqliteCreateTable::Constraint*}
+%destructor tcons {delete $$;}
+tcons(X) ::= CONSTRAINT nm(N). {
+ X = new SqliteCreateTable::Constraint();
+ X->initNameOnly(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+tcons(X) ::= PRIMARY KEY LP idxlist(L)
+ RP onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initPk(*(L), false, *(C));
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+tcons(X) ::= UNIQUE LP idxlist(L) RP
+ onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initUnique(*(L), *(C));
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+tcons(X) ::= CHECK LP expr(E) RP onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initCheck(E, *(C));
+ objectForTokens = X;
+ }
+tcons(X) ::= FOREIGN KEY LP idxlist(L) RP
+ REFERENCES nm(N) idxlist_opt(IL)
+ refargs(R) defer_subclause_opt(D). {
+ X = new SqliteCreateTable::Constraint();
+ X->initFk(
+ *(L),
+ *(N),
+ *(IL),
+ *(R),
+ D->initially,
+ D->deferrable
+ );
+ delete N;
+ delete R;
+ delete D;
+ delete IL;
+ delete L;
+ objectForTokens = X;
+ }
+
+tcons ::= CONSTRAINT ID_CONSTR. {}
+tcons ::= FOREIGN KEY LP idxlist RP
+ REFERENCES ID_TAB. {}
+tcons(X) ::= CHECK LP RP onconf. {
+ X = new SqliteCreateTable::Constraint();
+ X->initCheck();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+%type defer_subclause_opt {ParserDeferSubClause*}
+%destructor defer_subclause_opt {delete $$;}
+defer_subclause_opt(X) ::= . {X = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);}
+defer_subclause_opt(X) ::=
+ defer_subclause(D). {X = D;}
+
+// The following is a non-standard extension that allows us to declare the
+// default behavior when there is a constraint conflict.
+%type onconf {SqliteConflictAlgo*}
+%destructor onconf {delete $$;}
+onconf(X) ::= . {X = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+onconf(X) ::= ON CONFLICT resolvetype(R). {X = R;}
+
+%type orconf {SqliteConflictAlgo*}
+%destructor orconf {delete $$;}
+orconf(X) ::= . {X = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+orconf(X) ::= OR resolvetype(R). {X = R;}
+
+%type resolvetype {SqliteConflictAlgo*}
+%destructor resolvetype {delete $$;}
+resolvetype(X) ::= ROLLBACK(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= ABORT(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= FAIL(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= IGNORE(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= REPLACE(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+
+////////////////////////// The DROP TABLE /////////////////////////////////////
+
+cmd(X) ::= DROP TABLE fullname(N). {
+ X = new SqliteDropTable(false, N->name1, N->name2);
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP TABLE nm DOT
+ ID_TAB. {}
+cmd ::= DROP TABLE ID_DB|ID_TAB. {}
+
+///////////////////// The CREATE VIEW statement /////////////////////////////
+
+cmd(X) ::= CREATE temp(T) VIEW
+ nm(N)
+ AS select(S). {
+ X = new SqliteCreateView(*(T), false, *(N), QString::null, S);
+ delete T;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= CREATE temp VIEW ID_VIEW_NEW. {}
+
+cmd(X) ::= DROP VIEW nm(N). {
+ X = new SqliteDropView(false, *(N), QString::null);
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP VIEW ID_VIEW. {}
+
+//////////////////////// The SELECT statement /////////////////////////////////
+
+cmd(X) ::= select_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type select_stmt {SqliteQuery*}
+%destructor select_stmt {delete $$;}
+select_stmt(X) ::= select(S). {
+ X = S;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+%type select {SqliteSelect*}
+%destructor select {delete $$;}
+select(X) ::= oneselect(S). {
+ X = SqliteSelect::append(S);
+ objectForTokens = X;
+ }
+select(X) ::= select(S1) multiselect_op(O)
+ oneselect(S2). {
+ X = SqliteSelect::append(S1, *(O), S2);
+ delete O;
+ objectForTokens = X;
+ }
+
+%type multiselect_op {SqliteSelect::CompoundOperator*}
+%destructor multiselect_op {delete $$;}
+multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);}
+multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);}
+multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);}
+multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);}
+
+%type oneselect {SqliteSelect::Core*}
+%destructor oneselect {delete $$;}
+oneselect(X) ::= SELECT distinct(D)
+ selcollist(L) from(F)
+ where_opt(W) groupby_opt(G)
+ having_opt(H)
+ orderby_opt(O)
+ limit_opt(LI). {
+ X = new SqliteSelect::Core(
+ *(D),
+ *(L),
+ F,
+ W,
+ *(G),
+ H,
+ *(O),
+ LI
+ );
+ delete L;
+ delete D;
+ delete G;
+ delete O;
+ objectForTokens = X;
+ }
+
+%type distinct {int*}
+%destructor distinct {delete $$;}
+distinct(X) ::= DISTINCT. {X = new int(1);}
+distinct(X) ::= ALL. {X = new int(2);}
+distinct(X) ::= . {X = new int(0);}
+
+// selcollist is a list of expressions that are to become the return
+// values of the SELECT statement. The "*" in statements like
+// "SELECT * FROM ..." is encoded as a special expression with an
+// opcode of TK_ALL.
+
+%type sclp {ParserResultColumnList*}
+%destructor sclp {delete $$;}
+sclp(X) ::= selcollist(L) COMMA. {X = L;}
+sclp(X) ::= . {X = new ParserResultColumnList();}
+
+%type selcollist {ParserResultColumnList*}
+%destructor selcollist {delete $$;}
+selcollist(X) ::= sclp(L) expr(E) as(N). {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ E,
+ N ? N->asKw : false,
+ N ? N->name : QString::null
+ );
+
+ L->append(obj);
+ X = L;
+ delete N;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L) STAR. {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(true);
+
+ L->append(obj);
+ X = L;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L) nm(N) DOT STAR. {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ true,
+ *(N)
+ );
+ L->append(obj);
+ X = L;
+ delete N;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L). {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = L;
+ }
+selcollist ::= sclp ID_TAB DOT STAR. {}
+
+// An option "AS <id>" phrase that can follow one of the expressions that
+// define the result set, or one of the tables in the FROM clause.
+
+%type as {ParserStubAlias*}
+%destructor as {delete $$;}
+as(X) ::= AS nm(N). {
+ X = new ParserStubAlias(*(N), true);
+ delete N;
+ }
+as(X) ::= ids(N). {
+ X = new ParserStubAlias(*(N), false);
+ delete N;
+ }
+as ::= AS ID_ALIAS. {}
+as ::= ID_ALIAS. {}
+as(X) ::= . {X = nullptr;}
+
+// A complete FROM clause.
+%type from {SqliteSelect::Core::JoinSource*}
+%destructor from {delete $$;}
+from(X) ::= . {X = nullptr;}
+from(X) ::= FROM joinsrc(L). {X = L;}
+
+%type joinsrc {SqliteSelect::Core::JoinSource*}
+%destructor joinsrc {delete $$;}
+joinsrc(X) ::= singlesrc(S) seltablist(L). {
+ X = new SqliteSelect::Core::JoinSource(
+ S,
+ *(L)
+ );
+ delete L;
+ objectForTokens = X;
+ }
+joinsrc(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::JoinSource();
+ objectForTokens = X;
+ }
+
+%type seltablist {ParserOtherSourceList*}
+%destructor seltablist {delete $$;}
+seltablist(X) ::= seltablist(L) joinop(O)
+ singlesrc(S)
+ joinconstr_opt(C). {
+ SqliteSelect::Core::JoinSourceOther* src =
+ new SqliteSelect::Core::JoinSourceOther(O, S, C);
+
+ L->append(src);
+ X = L;
+ objectForTokens = src;
+ DONT_INHERIT_TOKENS("seltablist");
+ }
+seltablist(X) ::= . {
+ X = new ParserOtherSourceList();
+ }
+
+%type singlesrc {SqliteSelect::Core::SingleSource*}
+%destructor singlesrc {delete $$;}
+singlesrc(X) ::= nm(N1) dbnm(N2) as(A). {
+ X = new SqliteSelect::Core::SingleSource(
+ *(N1),
+ *(N2),
+ A ? A->asKw : false,
+ A ? A->name : QString::null,
+ false,
+ QString::null
+ );
+ delete N1;
+ delete N2;
+ delete A;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= LP select(S) RP as(A). {
+ X = new SqliteSelect::Core::SingleSource(
+ S,
+ A ? A->asKw : false,
+ A ? A->name : QString::null
+ );
+ delete A;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= LP joinsrc(J) RP as(A). {
+ X = new SqliteSelect::Core::SingleSource(
+ J,
+ A ? A->asKw : false,
+ A ? A->name : QString::null
+ );
+ delete A;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::SingleSource();
+ objectForTokens = X;
+ }
+singlesrc(X) ::= nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::SingleSource();
+ X->database = *(N);
+ delete N;
+ objectForTokens = X;
+ }
+
+singlesrc ::= nm DOT ID_TAB. {}
+singlesrc ::= ID_DB|ID_TAB. {}
+singlesrc ::= nm DOT ID_VIEW. {}
+singlesrc ::= ID_DB|ID_VIEW. {}
+
+%type joinconstr_opt {SqliteSelect::Core::JoinConstraint*}
+%destructor joinconstr_opt {delete $$;}
+joinconstr_opt(X) ::= ON expr(E). {
+ X = new SqliteSelect::Core::JoinConstraint(E);
+ objectForTokens = X;
+ }
+joinconstr_opt(X) ::= USING LP
+ inscollist(L) RP. {
+ X = new SqliteSelect::Core::JoinConstraint(*(L));
+ delete L;
+ objectForTokens = X;
+ }
+joinconstr_opt(X) ::= . {X = nullptr;}
+
+%type dbnm {QString*}
+%destructor dbnm {delete $$;}
+dbnm(X) ::= . {X = new QString();}
+dbnm(X) ::= DOT nm(N). {X = N;}
+
+%type fullname {ParserFullName*}
+%destructor fullname {delete $$;}
+fullname(X) ::= nm(N1) dbnm(N2). {
+ X = new ParserFullName();
+ X->name1 = *(N1);
+ X->name2 = *(N2);
+ delete N1;
+ delete N2;
+ }
+
+%type joinop {SqliteSelect::Core::JoinOp*}
+%destructor joinop {delete $$;}
+joinop(X) ::= COMMA. {
+ X = new SqliteSelect::Core::JoinOp(true);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN. {
+ X = new SqliteSelect::Core::JoinOp(false);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) nm(N) JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value, *(N));
+ delete N;
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) nm(N1) nm(N2)
+ JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value, *(N1), *(N2));
+ delete N1;
+ delete N1;
+ objectForTokens = X;
+ }
+
+joinop ::= ID_JOIN_OPTS. {}
+
+%type orderby_opt {ParserOrderByList*}
+%destructor orderby_opt {delete $$;}
+orderby_opt(X) ::= . {X = new ParserOrderByList();}
+orderby_opt(X) ::= ORDER BY sortlist(L). {X = L;}
+
+%type sortlist {ParserOrderByList*}
+%destructor sortlist {delete $$;}
+sortlist(X) ::= sortlist(L) COMMA
+ collate(C)
+ expr(E) sortorder(O). {
+ SqliteOrderBy* obj;
+ if (C)
+ {
+ SqliteExpr* coll = new SqliteExpr();
+ coll->initCollate(E, *(C));
+ delete C;
+ obj = new SqliteOrderBy(coll, *(O));
+ }
+ else
+ {
+ obj = new SqliteOrderBy(E, *(O));
+ }
+ L->append(obj);
+ X = L;
+ delete O;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sortlist");
+ }
+sortlist(X) ::= expr(E) collate(C)
+ sortorder(O). {
+ SqliteOrderBy* obj;
+ if (C)
+ {
+ SqliteExpr* coll = new SqliteExpr();
+ coll->initCollate(E, *(C));
+ delete C;
+ obj = new SqliteOrderBy(coll, *(O));
+ }
+ else
+ {
+ obj = new SqliteOrderBy(E, *(O));
+ }
+ X = new ParserOrderByList();
+ X->append(obj);
+ delete O;
+ objectForTokens = obj;
+ }
+
+%type collate {QString*}
+%destructor collate {if ($$) delete $$;}
+collate(X) ::= . {X = nullptr;}
+collate(X) ::= COLLATE id(I). {X = I;}
+
+%type sortorder {SqliteSortOrder*}
+%destructor sortorder {delete $$;}
+sortorder(X) ::= ASC. {X = new SqliteSortOrder(SqliteSortOrder::ASC);}
+sortorder(X) ::= DESC. {X = new SqliteSortOrder(SqliteSortOrder::DESC);}
+sortorder(X) ::= . {X = new SqliteSortOrder(SqliteSortOrder::null);}
+
+%type groupby_opt {ParserExprList*}
+%destructor groupby_opt {delete $$;}
+groupby_opt(X) ::= . {X = new ParserExprList();}
+groupby_opt(X) ::= GROUP BY nexprlist(L). {X = L;}
+groupby_opt(X) ::= GROUP BY. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserExprList();
+ }
+%type having_opt {SqliteExpr*}
+%destructor having_opt {delete $$;}
+having_opt(X) ::= . {X = nullptr;}
+having_opt(X) ::= HAVING expr(E). {X = E;}
+
+%type limit_opt {SqliteLimit*}
+%destructor limit_opt {delete $$;}
+limit_opt(X) ::= . {X = nullptr;}
+limit_opt(X) ::= LIMIT signed(V). {
+ X = new SqliteLimit(*(V));
+ delete V;
+ objectForTokens = X;
+ }
+limit_opt(X) ::= LIMIT signed(V1) OFFSET
+ signed(V2). {
+ SqliteExpr* expr1 = new SqliteExpr();
+ expr1->initLiteral(*(V1));
+ expr1->setParent(X);
+
+ SqliteExpr* expr2 = new SqliteExpr();
+ expr1->initLiteral(*(V2));
+ expr1->setParent(X);
+
+ X = new SqliteLimit(expr1, expr2, true);
+
+ TokenPtr limitToken = TokenPtr::create(Token::INTEGER, V1->toString());
+ parserContext->addManagedToken(limitToken);
+ expr1->tokens << limitToken;
+ expr1->tokensMap["term"] << limitToken;
+
+ TokenPtr offsetToken = TokenPtr::create(Token::INTEGER, V2->toString());
+ parserContext->addManagedToken(offsetToken);
+ expr2->tokens << offsetToken;
+ expr2->tokensMap["term"] << offsetToken;
+
+ delete V1;
+ delete V2;
+ objectForTokens = X;
+ }
+limit_opt(X) ::= LIMIT signed(V1) COMMA
+ signed(V2). {
+ SqliteExpr* expr1 = new SqliteExpr();
+ expr1->initLiteral(*(V1));
+ expr1->setParent(X);
+
+ SqliteExpr* expr2 = new SqliteExpr();
+ expr1->initLiteral(*(V2));
+ expr1->setParent(X);
+
+ X = new SqliteLimit(expr1, expr2, false);
+
+ TokenPtr limitToken = TokenPtr::create(Token::INTEGER, V1->toString());
+ parserContext->addManagedToken(limitToken);
+ expr1->tokens << limitToken;
+ expr1->tokensMap["term"] << limitToken;
+
+ TokenPtr offsetToken = TokenPtr::create(Token::INTEGER, V2->toString());
+ parserContext->addManagedToken(offsetToken);
+ expr2->tokens << offsetToken;
+ expr2->tokensMap["term"] << offsetToken;
+
+ delete V1;
+ delete V2;
+ objectForTokens = X;
+ }
+
+/////////////////////////// The DELETE statement /////////////////////////////
+
+cmd(X) ::= delete_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type delete_stmt {SqliteQuery*}
+%destructor delete_stmt {delete $$;}
+delete_stmt(X) ::= DELETE FROM fullname(N)
+ where_opt(W). {
+ X = new SqliteDelete(
+ N->name1,
+ N->name2,
+ false,
+ W,
+ nullptr
+ );
+ delete N;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+delete_stmt(X) ::= DELETE FROM. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ X = q;
+ objectForTokens = X;
+ }
+delete_stmt(X) ::= DELETE FROM nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete N;
+ }
+delete_stmt ::= DELETE FROM nm DOT ID_TAB. {}
+delete_stmt ::= DELETE FROM ID_DB|ID_TAB. {}
+
+%type where_opt {SqliteExpr*}
+%destructor where_opt {delete $$;}
+where_opt(X) ::= . {X = nullptr;}
+where_opt(X) ::= WHERE expr(E). {X = E;}
+where_opt(X) ::= WHERE. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteExpr();
+ }
+
+
+////////////////////////// The UPDATE command ////////////////////////////////
+
+cmd(X) ::= update_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type update_stmt {SqliteQuery*}
+%destructor update_stmt {delete $$;}
+update_stmt(X) ::= UPDATE orconf(C)
+ fullname(N) SET
+ setlist(L) where_opt(W). {
+ X = new SqliteUpdate(
+ *(C),
+ N->name1,
+ N->name2,
+ false,
+ QString::null,
+ *(L),
+ W,
+ nullptr
+ );
+ delete C;
+ delete N;
+ delete L;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+update_stmt(X) ::= UPDATE
+ orconf(C). {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteUpdate();
+ objectForTokens = X;
+ delete C;
+ }
+update_stmt(X) ::= UPDATE
+ orconf(C) nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete C;
+ delete N;
+ }
+update_stmt ::= UPDATE orconf nm DOT
+ ID_TAB. {}
+update_stmt ::= UPDATE orconf ID_DB|ID_TAB. {}
+
+%type setlist {ParserSetValueList*}
+%destructor setlist {delete $$;}
+setlist(X) ::= setlist(L) COMMA nm(N) EQ
+ expr(E). {
+ L->append(ParserSetValue(*(N), E));
+ X = L;
+ delete N;
+ DONT_INHERIT_TOKENS("setlist");
+ }
+setlist(X) ::= nm(N) EQ expr(E). {
+ X = new ParserSetValueList();
+ X->append(ParserSetValue(*(N), E));
+ delete N;
+ }
+setlist(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserSetValueList();
+ }
+setlist(X) ::= setlist(L) COMMA. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = L;
+ }
+
+setlist ::= setlist COMMA ID_COL. {}
+setlist ::= ID_COL. {}
+
+////////////////////////// The INSERT command /////////////////////////////////
+
+cmd(X) ::= insert_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type insert_stmt {SqliteQuery*}
+%destructor insert_stmt {delete $$;}
+insert_stmt(X) ::= insert_cmd(C) INTO
+ fullname(N) inscollist_opt(I)
+ VALUES LP exprlist(L) RP. {
+ X = new SqliteInsert(
+ C->replace,
+ C->orConflict,
+ N->name1,
+ N->name2,
+ *(I),
+ *(L),
+ nullptr
+ );
+ delete N;
+ delete C;
+ delete L;
+ delete I;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+insert_stmt(X) ::= insert_cmd(C) INTO
+ fullname(N) inscollist_opt(I)
+ select(S). {
+ X = new SqliteInsert(
+ C->replace,
+ C->orConflict,
+ N->name1,
+ N->name2,
+ *(I),
+ S,
+ nullptr
+ );
+ delete N;
+ delete C;
+ delete I;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+insert_stmt(X) ::= insert_cmd(C) INTO. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = C->replace;
+ q->onConflict = C->orConflict;
+ X = q;
+ objectForTokens = X;
+ delete C;
+ }
+insert_stmt(X) ::= insert_cmd(C) INTO nm(N)
+ DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = C->replace;
+ q->onConflict = C->orConflict;
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete C;
+ delete N;
+ }
+insert_stmt ::= insert_cmd INTO
+ ID_DB|ID_TAB. {}
+insert_stmt ::= insert_cmd INTO
+ nm DOT ID_TAB. {}
+
+%type insert_cmd {ParserStubInsertOrReplace*}
+%destructor insert_cmd {delete $$;}
+insert_cmd(X) ::= INSERT orconf(C). {
+ X = new ParserStubInsertOrReplace(false, *(C));
+ delete C;
+ }
+insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);}
+
+%type inscollist_opt {ParserStringList*}
+%destructor inscollist_opt {delete $$;}
+inscollist_opt(X) ::= . {X = new ParserStringList();}
+inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;}
+
+%type inscollist {ParserStringList*}
+%destructor inscollist {delete $$;}
+inscollist(X) ::= inscollist(L) COMMA
+ nm(N). {
+ L->append(*(N));
+ X = L;
+ delete N;
+ DONT_INHERIT_TOKENS("inscollist");
+ }
+inscollist(X) ::= nm(N). {
+ X = new ParserStringList();
+ X->append(*(N));
+ delete N;
+ }
+inscollist(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserStringList();
+ }
+
+inscollist ::= inscollist COMMA ID_COL. {}
+inscollist ::= ID_COL. {}
+
+/////////////////////////// Expression Processing /////////////////////////////
+
+%type exprx {SqliteExpr*}
+%destructor exprx {delete $$;}
+exprx(X) ::= NULL. {
+ X = new SqliteExpr();
+ X->initNull();
+ objectForTokens = X;
+ }
+exprx(X) ::= INTEGER(I). {
+ X = new SqliteExpr();
+ QVariant val = QVariant(I->value).toLongLong();
+ X->initLiteral(val);
+ objectForTokens = X;
+ }
+exprx(X) ::= FLOAT(F). {
+ X = new SqliteExpr();
+ QVariant val = QVariant(F->value).toDouble();
+ X->initLiteral(val);
+ objectForTokens = X;
+ }
+exprx(X) ::= STRING(S). {
+ X = new SqliteExpr();
+ X->initLiteral(QVariant(S->value));
+ objectForTokens = X;
+ }
+exprx(X) ::= LP expr(E) RP. {
+ X = new SqliteExpr();
+ X->initSubExpr(E);
+ objectForTokens = X;
+ }
+exprx(X) ::= id(N). {
+ X = new SqliteExpr();
+ X->initId(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= JOIN_KW(N). {
+ X = new SqliteExpr();
+ X->initId(N->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT nm(N2). {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2));
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT nm(N2) DOT nm(N3). {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2), *(N3));
+ delete N1;
+ delete N2;
+ delete N3;
+ objectForTokens = X;
+ }
+exprx(X) ::= VARIABLE(V). {
+ X = new SqliteExpr();
+ X->initBindParam(V->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= ID(I) LP exprlist(L) RP. {
+ X = new SqliteExpr();
+ X->initFunction(I->value, false, *(L));
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= ID(I) LP STAR RP. {
+ X = new SqliteExpr();
+ X->initFunction(I->value, true);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) AND(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) OR(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) LT|GT|GE|LE(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) EQ|NE(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1)
+ BITAND|BITOR|LSHIFT|RSHIFT(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) PLUS|MINUS(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) STAR|SLASH|REM(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) CONCAT(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) not_opt(N) likeop(L)
+ expr(E2). [LIKE_KW] {
+ X = new SqliteExpr();
+ X->initLike(E1, *(N), *(L), E2);
+ delete N;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) ISNULL|NOTNULL(N). {
+ X = new SqliteExpr();
+ X->initNull(E, N->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) NOT NULL. {
+ X = new SqliteExpr();
+ X->initNull(E, "NOT NULL");
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) IS not_opt(N)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initIs(E1, *(N), E2);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= NOT(O) expr(E). {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ }
+exprx(X) ::= BITNOT(O) expr(E). {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= MINUS(O) expr(E). [BITNOT] {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= PLUS(O) expr(E). [BITNOT] {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) not_opt(N) BETWEEN
+ expr(E2) AND
+ expr(E3). [BETWEEN] {
+ X = new SqliteExpr();
+ X->initBetween(E1, *(N), E2, E3);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ exprlist(L) RP. [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, *(N), *(L));
+ delete N;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ select(S) RP. [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, *(N), S);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN nm(N1)
+ dbnm(N2). [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, N, *(N1), *(N2));
+ delete N;
+ delete N1;
+ objectForTokens = X;
+ }
+exprx(X) ::= LP select(S) RP. {
+ X = new SqliteExpr();
+ X->initSubSelect(S);
+ objectForTokens = X;
+ }
+exprx(X) ::= CASE case_operand(O)
+ case_exprlist(L)
+ case_else(E) END. {
+ X = new SqliteExpr();
+ X->initCase(O, *(L), E);
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= RAISE LP raisetype(R) COMMA
+ nm(N) RP. {
+ X = new SqliteExpr();
+ X->initRaise(R->value, *(N));
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= RAISE LP IGNORE(R) RP. {
+ X = new SqliteExpr();
+ X->initRaise(R->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT. {
+ X = new SqliteExpr();
+ X->initId(*(N1), QString::null, QString::null);
+ delete N1;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= nm(N1) DOT nm(N2) DOT. {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2), QString::null);
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= expr(E1) not_opt(N) BETWEEN
+ expr(E2). [BETWEEN] {
+ X = new SqliteExpr();
+ delete N;
+ delete E1;
+ delete E2;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= CASE case_operand(O)
+ case_exprlist(L)
+ case_else(E). {
+ X = new SqliteExpr();
+ delete L;
+ delete O;
+ delete E;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ exprlist(L). [IN] {
+ X = new SqliteExpr();
+ delete N;
+ delete L;
+ delete E;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+
+exprx ::= expr not_opt IN ID_DB. [IN] {}
+exprx ::= expr not_opt IN nm DOT
+ ID_TAB. [IN] {}
+exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN. {}
+exprx ::= nm DOT ID_TAB|ID_COL. {}
+exprx ::= nm DOT nm DOT ID_COL. {}
+exprx ::= RAISE LP raisetype COMMA
+ ID_ERR_MSG RP. {}
+
+%type expr {SqliteExpr*}
+%destructor expr {delete $$;}
+expr(X) ::= exprx(E). {X = E;}
+expr(X) ::= . {
+ X = new SqliteExpr();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+%type not_opt {bool*}
+%destructor not_opt {delete $$;}
+not_opt(X) ::= . {X = new bool(false);}
+not_opt(X) ::= NOT. {X = new bool(true);}
+
+%type likeop {SqliteExpr::LikeOp*}
+%destructor likeop {delete $$;}
+likeop(X) ::= LIKE|GLOB(T). {X = new SqliteExpr::LikeOp(SqliteExpr::likeOp(T->value));}
+
+%type case_exprlist {ParserExprList*}
+%destructor case_exprlist {delete $$;}
+case_exprlist(X) ::= case_exprlist(L) WHEN
+ expr(E1) THEN expr(E2). {
+ L->append(E1);
+ L->append(E2);
+ X = L;
+ }
+case_exprlist(X) ::= WHEN expr(E1) THEN
+ expr(E2). {
+ X = new ParserExprList();
+ X->append(E1);
+ X->append(E2);
+ }
+
+%type case_else {SqliteExpr*}
+%destructor case_else {delete $$;}
+case_else(X) ::= ELSE expr(E). {X = E;}
+case_else(X) ::= . {X = nullptr;}
+
+%type case_operand {SqliteExpr*}
+%destructor case_operand {delete $$;}
+case_operand(X) ::= exprx(E). {X = E;}
+case_operand(X) ::= . {X = nullptr;}
+
+%type exprlist {ParserExprList*}
+%destructor exprlist {delete $$;}
+exprlist(X) ::= nexprlist(L). {X = L;}
+exprlist(X) ::= . {X = new ParserExprList();}
+
+%type nexprlist {ParserExprList*}
+%destructor nexprlist {delete $$;}
+nexprlist(X) ::= nexprlist(L) COMMA
+ expr(E). {
+ L->append(E);
+ X = L;
+ DONT_INHERIT_TOKENS("nexprlist");
+ }
+nexprlist(X) ::= exprx(E). {
+ X = new ParserExprList();
+ X->append(E);
+ }
+
+///////////////////////////// The CREATE INDEX command ///////////////////////
+
+cmd(X) ::= CREATE uniqueflag(U) INDEX
+ nm(N1) ON nm(N2) dbnm(N3)
+ LP idxlist(L) RP onconf(C). {
+ X = new SqliteCreateIndex(
+ *(U),
+ false,
+ *(N1),
+ *(N2),
+ *(N3),
+ *(L),
+ *(C)
+ );
+ delete U;
+ delete N1;
+ delete N2;
+ delete N3;
+ delete L;
+ delete C;
+ objectForTokens = X;
+ }
+
+cmd ::= CREATE uniqueflag INDEX nm dbnm
+ ON ID_TAB. {}
+cmd ::= CREATE uniqueflag INDEX nm DOT
+ ID_IDX_NEW. {}
+cmd ::= CREATE uniqueflag INDEX
+ ID_DB|ID_IDX_NEW. {}
+
+%type uniqueflag {bool*}
+%destructor uniqueflag {delete $$;}
+uniqueflag(X) ::= UNIQUE. {X = new bool(true);}
+uniqueflag(X) ::= . {X = new bool(false);}
+
+%type idxlist_opt {ParserIndexedColumnList*}
+%destructor idxlist_opt {delete $$;}
+idxlist_opt(X) ::= . {X = new ParserIndexedColumnList();}
+idxlist_opt(X) ::= LP idxlist(I) RP. {X = I;}
+
+%type idxlist {ParserIndexedColumnList*}
+%destructor idxlist {delete $$;}
+idxlist(X) ::= idxlist(L) COMMA
+ idxlist_single(S). {
+ L->append(S);
+ X = L;
+ DONT_INHERIT_TOKENS("idxlist");
+ }
+idxlist(X) ::= idxlist_single(S). {
+ X = new ParserIndexedColumnList();
+ X->append(S);
+ }
+
+%type idxlist_single {SqliteIndexedColumn*}
+%destructor idxlist_single {delete $$;}
+idxlist_single(X) ::= nm(N) sortorder(S). {
+ SqliteIndexedColumn* obj =
+ new SqliteIndexedColumn(
+ *(N),
+ QString::null,
+ *(S)
+ );
+ X = obj;
+ delete S;
+ delete N;
+ objectForTokens = X;
+ }
+
+idxlist_single ::= ID_COL. {}
+
+///////////////////////////// The DROP INDEX command /////////////////////////
+
+cmd(X) ::= DROP INDEX fullname(N). {
+ X = new SqliteDropIndex(false, N->name1, N->name2);
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP INDEX nm DOT ID_IDX. {}
+cmd ::= DROP INDEX ID_DB|ID_IDX. {}
+
+///////////////////////////// The COPY command ///////////////////////////////
+
+cmd(X) ::= COPY orconf(C) nm(N1) dbnm(N2)
+ FROM nm(N3) USING DELIMITERS
+ STRING(S). {
+ X = new SqliteCopy(
+ *(C),
+ *(N1),
+ *(N2),
+ *(N3),
+ S->value
+ );
+ delete C;
+ delete N1;
+ delete N2;
+ delete N3;
+ objectForTokens = X;
+ }
+cmd(X) ::= COPY orconf(C) nm(N1) dbnm(N2)
+ FROM nm(N3). {
+ X = new SqliteCopy(
+ *(C),
+ *(N1),
+ *(N2),
+ *(N3)
+ );
+ delete C;
+ delete N1;
+ delete N2;
+ delete N3;
+ objectForTokens = X;
+ }
+
+///////////////////////////// The VACUUM command /////////////////////////////
+
+cmd(X) ::= VACUUM. {
+ X = new SqliteVacuum();
+ objectForTokens = X;
+ }
+cmd(X) ::= VACUUM nm(N). {
+ X = new SqliteVacuum(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+
+///////////////////////////// The PRAGMA command /////////////////////////////
+
+cmd(X) ::= PRAGMA ids(I). {
+ X = new SqlitePragma(*(I), QString::null);
+ delete I;
+ objectForTokens = X;
+ }
+
+cmd(X) ::= PRAGMA nm(N) EQ nmnum(V). {
+ X = new SqlitePragma(*(N), QString::null, *(V), true);
+ delete N;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N) LP nmnum(V) RP. {
+ X = new SqlitePragma(*(N), QString::null, *(V), false);
+ delete N;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N) EQ minus_num(V). {
+ X = new SqlitePragma(*(N), QString::null, *(V), true);
+ delete N;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N) LP minus_num(V) RP. {
+ X = new SqlitePragma(*(N), QString::null, *(V), false);
+ delete N;
+ delete V;
+ objectForTokens = X;
+ }
+
+cmd ::= PRAGMA nm DOT ID_PRAGMA. {}
+cmd ::= PRAGMA ID_DB|ID_PRAGMA. {}
+
+%type nmnum {QVariant*}
+%destructor nmnum {delete $$;}
+nmnum(X) ::= plus_num(N). {X = N;}
+nmnum(X) ::= nm(N). {
+ X = new QVariant(*(N));
+ delete N;
+ }
+nmnum(X) ::= ON(T). {X = new QVariant(T->value);}
+nmnum(X) ::= DELETE(T). {X = new QVariant(T->value);}
+nmnum(X) ::= DEFAULT(T). {X = new QVariant(T->value);}
+
+%type plus_num {QVariant*}
+%destructor plus_num {delete $$;}
+plus_num(X) ::= PLUS number(N). {X = N;}
+plus_num(X) ::= number(N). {X = N;}
+
+%type minus_num {QVariant*}
+%destructor minus_num {delete $$;}
+minus_num(X) ::= MINUS number(N). {
+ if (N->type() == QVariant::Double)
+ *(N) = -(N->toDouble());
+ else if (N->type() == QVariant::LongLong)
+ *(N) = -(N->toLongLong());
+ else
+ Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong.");
+
+ X = N;
+ }
+
+%type number {QVariant*}
+%destructor number {delete $$;}
+number(X) ::= INTEGER(N). {X = new QVariant(QVariant(N->value).toLongLong());}
+number(X) ::= FLOAT(N). {X = new QVariant(QVariant(N->value).toDouble());}
+
+//////////////////////////// The CREATE TRIGGER command /////////////////////
+
+cmd(X) ::= CREATE temp(T) TRIGGER
+ nm(N) trigger_time(TT)
+ trigger_event(EV) ON nm(N1)
+ dbnm(N2) foreach_clause(FC)
+ when_clause(WC) BEGIN
+ trigger_cmd_list(CL) END. {
+ X = new SqliteCreateTrigger(
+ *(T),
+ false,
+ *(N),
+ *(N1),
+ *(N2),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ *(CL),
+ 2
+ );
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ delete CL;
+ objectForTokens = X;
+ }
+
+// Support full parsing when no BEGIN and END are present (for completion helper)
+cmd(X) ::= CREATE temp(T) TRIGGER
+ nm(N) trigger_time(TT)
+ trigger_event(EV) ON nm(N1)
+ dbnm(N2) foreach_clause(FC)
+ when_clause(WC). {
+ QList<SqliteQuery *> CL;
+
+ X = new SqliteCreateTrigger(
+ *(T),
+ false,
+ *(N),
+ *(N1),
+ *(N2),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ CL,
+ 2
+ );
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+// Support full parsing when no END is present (for completion helper)
+cmd(X) ::= CREATE temp(T) TRIGGER
+ nm(N) trigger_time(TT)
+ trigger_event(EV) ON nm(N1)
+ dbnm(N2) foreach_clause(FC)
+ when_clause(WC) BEGIN
+ trigger_cmd_list(CL). {
+ X = new SqliteCreateTrigger(
+ *(T),
+ false,
+ *(N),
+ *(N1),
+ *(N2),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ *(CL),
+ 2
+ );
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ delete CL;
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+cmd ::= CREATE temp TRIGGER nm
+ trigger_time trigger_event
+ ON ID_TAB|ID_DB. {}
+cmd ::= CREATE temp TRIGGER nm
+ trigger_time trigger_event
+ ON nm DOT ID_TAB. {}
+cmd ::= CREATE temp TRIGGER ID_TRIG_NEW. {}
+
+%type trigger_time {SqliteCreateTrigger::Time*}
+%destructor trigger_time {delete $$;}
+trigger_time(X) ::= BEFORE. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);}
+trigger_time(X) ::= AFTER. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);}
+trigger_time(X) ::= INSTEAD OF. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);}
+trigger_time(X) ::= . {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);}
+
+%type trigger_event {SqliteCreateTrigger::Event*}
+%destructor trigger_event {delete $$;}
+trigger_event(X) ::= DELETE. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= INSERT. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= UPDATE. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= UPDATE OF
+ inscollist(L). {
+ X = new SqliteCreateTrigger::Event(*(L));
+ delete L;
+ objectForTokens = X;
+ }
+
+%type foreach_clause {SqliteCreateTrigger::Scope*}
+%destructor foreach_clause {delete $$;}
+foreach_clause(X) ::= . {X = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);}
+foreach_clause(X) ::= FOR EACH ROW. {X = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);}
+foreach_clause(X) ::= FOR EACH STATEMENT. {X = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_STATEMENT);}
+
+%type when_clause {SqliteExpr*}
+%destructor when_clause {if ($$) delete $$;}
+when_clause(X) ::= . {X = nullptr;}
+when_clause(X) ::= WHEN expr(E). {X = E;}
+
+%type trigger_cmd_list {ParserQueryList*}
+%destructor trigger_cmd_list {delete $$;}
+trigger_cmd_list(X) ::= trigger_cmd_list(L)
+ trigger_cmd(C) SEMI. {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("trigger_cmd_list");
+ }
+trigger_cmd_list(X) ::= trigger_cmd(C)
+ SEMI. {
+ X = new ParserQueryList();
+ X->append(C);
+ }
+
+%type trigger_cmd {SqliteQuery*}
+%destructor trigger_cmd {delete $$;}
+trigger_cmd(X) ::= update_stmt(S). {X = S;}
+trigger_cmd(X) ::= insert_stmt(S). {X = S;}
+trigger_cmd(X) ::= delete_stmt(S). {X = S;}
+trigger_cmd(X) ::= select_stmt(S). {X = S;}
+
+%type raisetype {Token*}
+raisetype(X) ::= ROLLBACK|ABORT|FAIL(V). {X = V;}
+
+//////////////////////// DROP TRIGGER statement //////////////////////////////
+cmd(X) ::= DROP TRIGGER fullname(N). {
+ X = new SqliteDropTrigger(false, N->name1, N->name2);
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP TRIGGER nm DOT ID_TRIG. {}
+cmd ::= DROP TRIGGER ID_DB|ID_TRIG. {}
+
+//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+cmd(X) ::= ATTACH database_kw_opt(D)
+ ids(I1) AS ids(I2) key_opt(K). {
+ SqliteExpr* e1 = new SqliteExpr();
+ SqliteExpr* e2 = new SqliteExpr();
+ e1->initLiteral(*(I1));
+ e2->initLiteral(*(I2));
+ X = new SqliteAttach(*(D), e1, e2, K);
+ delete D;
+ delete I1;
+ delete I2;
+ objectForTokens = X;
+ }
+
+%type key_opt {SqliteExpr*}
+%destructor key_opt {if ($$) delete $$;}
+key_opt(X) ::= . {X = nullptr;}
+key_opt(X) ::= USING ids(I). {
+ SqliteExpr* e = new SqliteExpr();
+ e->initLiteral(*(I));
+ delete I;
+ X = e;
+ }
+
+%type database_kw_opt {bool*}
+%destructor database_kw_opt {delete $$;}
+database_kw_opt(X) ::= DATABASE. {X = new bool(true);}
+database_kw_opt(X) ::= . {X = new bool(false);}
+
+
+//////////////////////// DETACH DATABASE name /////////////////////////////////
+cmd(X) ::= DETACH database_kw_opt(D)
+ nm(N). {
+ SqliteExpr* e = new SqliteExpr();
+ e->initLiteral(*(N));
+ delete N;
+ X = new SqliteDetach(*(D), e);
+ delete D;
+ objectForTokens = X;
+ }
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp
new file mode 100644
index 0000000..3bdd9a4
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.cpp
@@ -0,0 +1,5262 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+**
+** This version of "lempar.c" is modified, slightly, for use by SQLite.
+** The only modifications are the addition of a couple of NEVER()
+** macros to disable tests that are needed in the case of a general
+** LALR(1) grammar but which are always false in the
+** specific grammar used by SQLite.
+*/
+/* First off, code is included that follows the "include" declaration
+** in the input grammar file. */
+#include <stdio.h>
+
+#include "token.h"
+#include "parsercontext.h"
+#include "parser_helper_stubs.h"
+#include "common/utils_sql.h"
+#include "parser/ast/sqlitealtertable.h"
+#include "parser/ast/sqliteanalyze.h"
+#include "parser/ast/sqliteattach.h"
+#include "parser/ast/sqlitebegintrans.h"
+#include "parser/ast/sqlitecommittrans.h"
+#include "parser/ast/sqlitecopy.h"
+#include "parser/ast/sqlitecreateindex.h"
+#include "parser/ast/sqlitecreatetable.h"
+#include "parser/ast/sqlitecreatetrigger.h"
+#include "parser/ast/sqlitecreateview.h"
+#include "parser/ast/sqlitecreatevirtualtable.h"
+#include "parser/ast/sqlitedelete.h"
+#include "parser/ast/sqlitedetach.h"
+#include "parser/ast/sqlitedropindex.h"
+#include "parser/ast/sqlitedroptable.h"
+#include "parser/ast/sqlitedroptrigger.h"
+#include "parser/ast/sqlitedropview.h"
+#include "parser/ast/sqliteemptyquery.h"
+#include "parser/ast/sqliteinsert.h"
+#include "parser/ast/sqlitepragma.h"
+#include "parser/ast/sqlitereindex.h"
+#include "parser/ast/sqliterelease.h"
+#include "parser/ast/sqliterollback.h"
+#include "parser/ast/sqlitesavepoint.h"
+#include "parser/ast/sqliteselect.h"
+#include "parser/ast/sqliteupdate.h"
+#include "parser/ast/sqlitevacuum.h"
+#include "parser/ast/sqliteexpr.h"
+#include "parser/ast/sqlitecolumntype.h"
+#include "parser/ast/sqliteconflictalgo.h"
+#include "parser/ast/sqlitesortorder.h"
+#include "parser/ast/sqliteindexedcolumn.h"
+#include "parser/ast/sqliteforeignkey.h"
+#include "parser/ast/sqlitewith.h"
+#include <QObject>
+#include <QDebug>
+
+#define assert(X) Q_ASSERT(X)
+#define UNUSED_PARAMETER(X) (void)(X)
+#define DONT_INHERIT_TOKENS(X) noTokenInheritanceFields << X
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** sqlite3_parseTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is sqlite3_parseTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
+** sqlite3_parseARG_SDECL A static variable declaration for the %extra_argument
+** sqlite3_parseARG_PDECL A parameter declaration for the %extra_argument
+** sqlite3_parseARG_STORE Code to store %extra_argument into yypParser
+** sqlite3_parseARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+#define YYCODETYPE unsigned short int
+#define YYNOCODE 278
+#define YYACTIONTYPE unsigned short int
+#define YYWILDCARD 61
+#define sqlite3_parseTOKENTYPE Token*
+typedef union {
+ int yyinit;
+ sqlite3_parseTOKENTYPE yy0;
+ SqliteCreateTable::Column::Constraint* yy4;
+ SqliteCreateTable::Constraint* yy8;
+ ParserExprList* yy13;
+ QVariant* yy21;
+ ParserStubAlias* yy28;
+ SqliteConflictAlgo* yy30;
+ ParserFullName* yy66;
+ ParserCreateTableConstraintList* yy87;
+ SqliteIndexedColumn* yy90;
+ ParserFkConditionList* yy108;
+ SqliteSelect::Core::JoinConstraint* yy117;
+ ParserCreateTableColumnList* yy118;
+ SqliteSelect* yy123;
+ SqliteLimit* yy128;
+ ParserDeferSubClause* yy131;
+ ParserIndexedColumnList* yy139;
+ SqliteCreateTrigger::Time* yy152;
+ SqliteSelect::CompoundOperator* yy168;
+ SqliteSelect::Core::SingleSource* yy173;
+ QString* yy211;
+ ParserQueryList* yy214;
+ ParserStubExplain* yy225;
+ SqliteSortOrder* yy226;
+ bool* yy237;
+ ParserStubInsertOrReplace* yy250;
+ ParserResultColumnList* yy263;
+ SqliteForeignKey::Condition* yy271;
+ SqliteColumnType* yy299;
+ ParserStubTransDetails* yy300;
+ SqliteCreateTrigger::Event* yy309;
+ SqliteForeignKey::Condition::Reaction* yy312;
+ ParserOtherSourceList* yy359;
+ SqliteWith* yy367;
+ SqliteSelect::Core::JoinSource* yy373;
+ SqliteExpr::LikeOp* yy374;
+ int* yy376;
+ ParserSetValueList* yy381;
+ SqliteQuery* yy399;
+ SqliteCreateTrigger::Scope* yy409;
+ ParserExprNestedList* yy416;
+ SqliteCreateTable::Column* yy425;
+ ParserStringList* yy445;
+ ParserCreateTableColumnConstraintList* yy449;
+ SqliteSelect::Core* yy468;
+ ParserIndexedBy* yy472;
+ SqliteSelect::Core::JoinOp* yy473;
+ SqliteExpr* yy490;
+ ParserOrderByList* yy495;
+ SqliteInitially* yy498;
+} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
+#define YYSTACKDEPTH 100
+#endif
+#define sqlite3_parseARG_SDECL ParserContext* parserContext;
+#define sqlite3_parseARG_PDECL ,ParserContext* parserContext
+#define sqlite3_parseARG_FETCH ParserContext* parserContext = yypParser->parserContext
+#define sqlite3_parseARG_STORE yypParser->parserContext = parserContext
+#define YYNSTATE 724
+#define YYNRULE 424
+#define YYFALLBACK 1
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+#define GET_CONTEXT yyParser* yypParser = pParser; sqlite3_parseARG_FETCH
+
+/* The yyzerominor constant is used to initialize instances of
+** YYMINORTYPE objects to zero. */
+static const YYMINORTYPE yyzerominor = { 0 };
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage. For production
+** code the yytestcase() macro should be turned off. But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+#define YY_ACTTAB_COUNT (2221)
+static const YYACTIONTYPE yy_action[] = {
+ /* 0 */ 431, 49, 49, 48, 48, 48, 47, 216, 716, 339,
+ /* 10 */ 643, 425, 52, 52, 52, 52, 45, 50, 50, 50,
+ /* 20 */ 50, 49, 49, 48, 48, 48, 47, 216, 721, 1026,
+ /* 30 */ 1026, 643, 131, 580, 52, 52, 52, 52, 411, 50,
+ /* 40 */ 50, 50, 50, 49, 49, 48, 48, 48, 47, 216,
+ /* 50 */ 579, 81, 58, 643, 157, 685, 301, 282, 1026, 1026,
+ /* 60 */ 42, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
+ /* 70 */ 1026, 1026, 563, 1026, 1026, 1026, 1026, 39, 40, 1026,
+ /* 80 */ 1026, 1026, 1026, 1026, 41, 431, 528, 385, 716, 595,
+ /* 90 */ 594, 280, 4, 377, 716, 630, 425, 642, 608, 422,
+ /* 100 */ 12, 134, 687, 429, 562, 609, 483, 690, 331, 279,
+ /* 110 */ 714, 713, 564, 565, 642, 689, 688, 687, 235, 506,
+ /* 120 */ 60, 320, 610, 411, 48, 48, 48, 47, 216, 122,
+ /* 130 */ 243, 213, 247, 59, 1142, 1142, 486, 609, 607, 603,
+ /* 140 */ 685, 306, 485, 584, 716, 42, 507, 509, 642, 508,
+ /* 150 */ 676, 9, 642, 144, 95, 281, 379, 276, 378, 132,
+ /* 160 */ 297, 716, 39, 40, 601, 200, 199, 7, 355, 41,
+ /* 170 */ 884, 307, 1134, 274, 249, 716, 17, 4, 884, 1134,
+ /* 180 */ 57, 717, 642, 431, 422, 884, 329, 687, 429, 716,
+ /* 190 */ 687, 643, 690, 687, 425, 690, 714, 713, 690, 642,
+ /* 200 */ 689, 688, 687, 689, 688, 687, 689, 688, 687, 98,
+ /* 210 */ 682, 240, 643, 218, 410, 884, 486, 884, 884, 483,
+ /* 220 */ 716, 411, 239, 884, 303, 582, 512, 581, 884, 884,
+ /* 230 */ 884, 884, 884, 642, 643, 676, 9, 642, 685, 217,
+ /* 240 */ 245, 673, 102, 42, 287, 300, 714, 713, 67, 302,
+ /* 250 */ 148, 307, 1133, 151, 306, 484, 81, 715, 97, 1133,
+ /* 260 */ 39, 40, 551, 714, 713, 771, 130, 41, 946, 376,
+ /* 270 */ 373, 372, 447, 47, 216, 4, 946, 714, 713, 334,
+ /* 280 */ 642, 682, 422, 946, 606, 687, 429, 371, 448, 447,
+ /* 290 */ 690, 714, 713, 304, 265, 146, 267, 642, 689, 688,
+ /* 300 */ 687, 287, 68, 677, 691, 255, 362, 259, 359, 692,
+ /* 310 */ 1027, 1027, 682, 946, 715, 946, 946, 447, 698, 234,
+ /* 320 */ 386, 715, 714, 713, 773, 651, 946, 946, 946, 946,
+ /* 330 */ 110, 642, 317, 676, 9, 642, 222, 677, 299, 53,
+ /* 340 */ 54, 426, 289, 1027, 1027, 675, 675, 51, 51, 52,
+ /* 350 */ 52, 52, 52, 716, 50, 50, 50, 50, 49, 49,
+ /* 360 */ 48, 48, 48, 47, 216, 431, 428, 340, 716, 335,
+ /* 370 */ 671, 670, 287, 283, 716, 138, 425, 209, 219, 430,
+ /* 380 */ 268, 395, 651, 682, 336, 715, 715, 686, 186, 53,
+ /* 390 */ 54, 426, 289, 715, 452, 675, 675, 51, 51, 52,
+ /* 400 */ 52, 52, 52, 411, 50, 50, 50, 50, 49, 49,
+ /* 410 */ 48, 48, 48, 47, 216, 91, 953, 716, 619, 712,
+ /* 420 */ 685, 403, 382, 130, 710, 42, 376, 373, 372, 711,
+ /* 430 */ 233, 953, 394, 311, 210, 593, 666, 384, 428, 16,
+ /* 440 */ 316, 659, 39, 40, 371, 231, 230, 716, 89, 41,
+ /* 450 */ 931, 430, 716, 658, 716, 714, 713, 4, 931, 686,
+ /* 460 */ 92, 143, 642, 358, 422, 931, 674, 687, 429, 14,
+ /* 470 */ 714, 713, 690, 131, 456, 551, 714, 713, 953, 642,
+ /* 480 */ 689, 688, 687, 668, 667, 210, 593, 458, 384, 457,
+ /* 490 */ 576, 88, 1027, 1027, 13, 931, 672, 931, 931, 55,
+ /* 500 */ 575, 678, 43, 368, 38, 401, 36, 381, 931, 1,
+ /* 510 */ 931, 931, 641, 642, 634, 676, 9, 642, 661, 714,
+ /* 520 */ 713, 53, 54, 426, 289, 1027, 1027, 675, 675, 51,
+ /* 530 */ 51, 52, 52, 52, 52, 660, 50, 50, 50, 50,
+ /* 540 */ 49, 49, 48, 48, 48, 47, 216, 657, 648, 714,
+ /* 550 */ 713, 496, 542, 569, 714, 713, 714, 713, 656, 691,
+ /* 560 */ 543, 614, 320, 30, 692, 27, 716, 585, 274, 682,
+ /* 570 */ 160, 1027, 1027, 426, 289, 693, 613, 675, 675, 51,
+ /* 580 */ 51, 52, 52, 52, 52, 398, 50, 50, 50, 50,
+ /* 590 */ 49, 49, 48, 48, 48, 47, 216, 1025, 1025, 81,
+ /* 600 */ 53, 54, 426, 289, 1027, 1027, 675, 675, 51, 51,
+ /* 610 */ 52, 52, 52, 52, 496, 50, 50, 50, 50, 49,
+ /* 620 */ 49, 48, 48, 48, 47, 216, 1025, 1025, 1025, 1025,
+ /* 630 */ 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025,
+ /* 640 */ 716, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025,
+ /* 650 */ 1025, 1025, 1027, 1027, 357, 50, 50, 50, 50, 49,
+ /* 660 */ 49, 48, 48, 48, 47, 216, 288, 552, 714, 713,
+ /* 670 */ 495, 682, 298, 662, 346, 153, 538, 69, 694, 715,
+ /* 680 */ 715, 53, 54, 426, 289, 1027, 1027, 675, 675, 51,
+ /* 690 */ 51, 52, 52, 52, 52, 1094, 50, 50, 50, 50,
+ /* 700 */ 49, 49, 48, 48, 48, 47, 216, 53, 54, 426,
+ /* 710 */ 289, 418, 511, 675, 675, 51, 51, 52, 52, 52,
+ /* 720 */ 52, 159, 50, 50, 50, 50, 49, 49, 48, 48,
+ /* 730 */ 48, 47, 216, 490, 954, 315, 482, 482, 663, 553,
+ /* 740 */ 215, 650, 714, 713, 81, 53, 54, 426, 289, 954,
+ /* 750 */ 414, 675, 675, 51, 51, 52, 52, 52, 52, 397,
+ /* 760 */ 50, 50, 50, 50, 49, 49, 48, 48, 48, 47,
+ /* 770 */ 216, 158, 1094, 21, 716, 627, 459, 716, 1079, 716,
+ /* 780 */ 647, 1045, 140, 89, 716, 1149, 154, 435, 2, 715,
+ /* 790 */ 424, 671, 670, 396, 460, 461, 954, 53, 54, 426,
+ /* 800 */ 289, 573, 716, 675, 675, 51, 51, 52, 52, 52,
+ /* 810 */ 52, 321, 50, 50, 50, 50, 49, 49, 48, 48,
+ /* 820 */ 48, 47, 216, 431, 1108, 81, 206, 205, 204, 53,
+ /* 830 */ 54, 426, 289, 716, 425, 675, 675, 51, 51, 52,
+ /* 840 */ 52, 52, 52, 344, 50, 50, 50, 50, 49, 49,
+ /* 850 */ 48, 48, 48, 47, 216, 597, 715, 666, 600, 462,
+ /* 860 */ 666, 411, 31, 716, 657, 90, 12, 894, 720, 668,
+ /* 870 */ 667, 609, 724, 434, 81, 656, 714, 713, 685, 714,
+ /* 880 */ 713, 714, 713, 42, 528, 272, 714, 713, 610, 349,
+ /* 890 */ 528, 450, 89, 677, 12, 633, 633, 338, 636, 609,
+ /* 900 */ 39, 40, 649, 609, 714, 713, 716, 41, 1142, 1142,
+ /* 910 */ 716, 524, 682, 581, 716, 4, 610, 468, 60, 450,
+ /* 920 */ 642, 208, 422, 506, 60, 687, 429, 677, 33, 109,
+ /* 930 */ 690, 609, 500, 501, 352, 714, 713, 642, 689, 688,
+ /* 940 */ 687, 428, 900, 900, 467, 466, 552, 465, 421, 383,
+ /* 950 */ 507, 509, 142, 508, 430, 440, 69, 1142, 1142, 715,
+ /* 960 */ 444, 722, 686, 182, 646, 714, 713, 645, 231, 230,
+ /* 970 */ 437, 642, 356, 676, 9, 642, 417, 444, 53, 54,
+ /* 980 */ 426, 289, 91, 91, 675, 675, 51, 51, 52, 52,
+ /* 990 */ 52, 52, 644, 50, 50, 50, 50, 49, 49, 48,
+ /* 1000 */ 48, 48, 47, 216, 1034, 444, 668, 667, 714, 713,
+ /* 1010 */ 91, 453, 714, 713, 682, 641, 714, 713, 324, 202,
+ /* 1020 */ 53, 54, 426, 289, 446, 680, 675, 675, 51, 51,
+ /* 1030 */ 52, 52, 52, 52, 639, 50, 50, 50, 50, 49,
+ /* 1040 */ 49, 48, 48, 48, 47, 216, 605, 53, 54, 426,
+ /* 1050 */ 289, 716, 446, 675, 675, 51, 51, 52, 52, 52,
+ /* 1060 */ 52, 459, 50, 50, 50, 50, 49, 49, 48, 48,
+ /* 1070 */ 48, 47, 216, 453, 715, 37, 663, 423, 215, 460,
+ /* 1080 */ 341, 369, 592, 53, 54, 426, 289, 638, 89, 675,
+ /* 1090 */ 675, 51, 51, 52, 52, 52, 52, 31, 50, 50,
+ /* 1100 */ 50, 50, 49, 49, 48, 48, 48, 47, 216, 413,
+ /* 1110 */ 723, 2, 11, 53, 54, 426, 289, 34, 588, 675,
+ /* 1120 */ 675, 51, 51, 52, 52, 52, 52, 624, 50, 50,
+ /* 1130 */ 50, 50, 49, 49, 48, 48, 48, 47, 216, 515,
+ /* 1140 */ 715, 537, 29, 91, 342, 666, 140, 8, 571, 53,
+ /* 1150 */ 54, 426, 289, 714, 713, 675, 675, 51, 51, 52,
+ /* 1160 */ 52, 52, 52, 548, 50, 50, 50, 50, 49, 49,
+ /* 1170 */ 48, 48, 48, 47, 216, 91, 252, 234, 386, 53,
+ /* 1180 */ 54, 426, 289, 89, 271, 675, 675, 51, 51, 52,
+ /* 1190 */ 52, 52, 52, 333, 50, 50, 50, 50, 49, 49,
+ /* 1200 */ 48, 48, 48, 47, 216, 532, 81, 682, 696, 338,
+ /* 1210 */ 87, 53, 54, 426, 289, 22, 557, 675, 675, 51,
+ /* 1220 */ 51, 52, 52, 52, 52, 615, 50, 50, 50, 50,
+ /* 1230 */ 49, 49, 48, 48, 48, 47, 216, 682, 1109, 91,
+ /* 1240 */ 504, 716, 53, 54, 426, 289, 604, 137, 675, 675,
+ /* 1250 */ 51, 51, 52, 52, 52, 52, 136, 50, 50, 50,
+ /* 1260 */ 50, 49, 49, 48, 48, 48, 47, 216, 431, 1107,
+ /* 1270 */ 135, 488, 388, 722, 53, 54, 426, 289, 308, 425,
+ /* 1280 */ 675, 675, 51, 51, 52, 52, 52, 52, 620, 50,
+ /* 1290 */ 50, 50, 50, 49, 49, 48, 48, 48, 47, 216,
+ /* 1300 */ 428, 552, 624, 428, 283, 716, 411, 517, 404, 682,
+ /* 1310 */ 697, 69, 829, 430, 715, 715, 430, 715, 464, 540,
+ /* 1320 */ 653, 686, 186, 685, 686, 186, 99, 428, 42, 716,
+ /* 1330 */ 390, 715, 226, 223, 599, 539, 5, 534, 534, 682,
+ /* 1340 */ 430, 91, 91, 714, 713, 39, 40, 682, 686, 186,
+ /* 1350 */ 555, 431, 41, 620, 620, 403, 405, 598, 403, 387,
+ /* 1360 */ 4, 570, 425, 629, 311, 642, 428, 422, 326, 10,
+ /* 1370 */ 687, 429, 716, 624, 316, 690, 716, 316, 428, 430,
+ /* 1380 */ 716, 620, 642, 689, 688, 687, 715, 686, 186, 411,
+ /* 1390 */ 716, 430, 498, 596, 716, 632, 499, 602, 612, 686,
+ /* 1400 */ 186, 406, 491, 591, 285, 631, 685, 714, 713, 266,
+ /* 1410 */ 590, 42, 716, 365, 209, 589, 642, 350, 676, 9,
+ /* 1420 */ 642, 332, 715, 261, 107, 611, 530, 221, 39, 40,
+ /* 1430 */ 225, 714, 713, 399, 431, 41, 715, 716, 283, 351,
+ /* 1440 */ 316, 138, 716, 4, 270, 425, 209, 286, 642, 682,
+ /* 1450 */ 422, 715, 316, 714, 429, 716, 209, 530, 690, 716,
+ /* 1460 */ 715, 19, 561, 491, 716, 642, 689, 688, 687, 525,
+ /* 1470 */ 375, 65, 411, 519, 714, 713, 273, 475, 714, 713,
+ /* 1480 */ 64, 370, 714, 713, 619, 18, 525, 514, 129, 685,
+ /* 1490 */ 519, 479, 714, 713, 42, 716, 714, 713, 227, 642,
+ /* 1500 */ 428, 676, 9, 642, 514, 63, 286, 428, 479, 475,
+ /* 1510 */ 622, 39, 40, 430, 714, 713, 431, 718, 41, 715,
+ /* 1520 */ 430, 686, 181, 715, 279, 716, 4, 425, 686, 163,
+ /* 1530 */ 715, 642, 366, 422, 472, 156, 687, 429, 533, 714,
+ /* 1540 */ 713, 690, 125, 3, 714, 713, 416, 79, 642, 689,
+ /* 1550 */ 688, 687, 469, 85, 411, 258, 438, 714, 713, 220,
+ /* 1560 */ 26, 714, 713, 25, 706, 407, 714, 713, 715, 77,
+ /* 1570 */ 704, 685, 510, 438, 641, 516, 42, 715, 716, 472,
+ /* 1580 */ 353, 641, 642, 715, 676, 9, 642, 503, 1035, 428,
+ /* 1590 */ 625, 536, 505, 39, 40, 83, 119, 714, 713, 428,
+ /* 1600 */ 41, 621, 430, 497, 428, 420, 254, 62, 4, 1037,
+ /* 1610 */ 686, 172, 430, 642, 140, 422, 469, 430, 687, 429,
+ /* 1620 */ 686, 189, 152, 690, 337, 686, 187, 714, 713, 251,
+ /* 1630 */ 642, 689, 688, 687, 161, 54, 426, 289, 716, 558,
+ /* 1640 */ 675, 675, 51, 51, 52, 52, 52, 52, 478, 50,
+ /* 1650 */ 50, 50, 50, 49, 49, 48, 48, 48, 47, 216,
+ /* 1660 */ 431, 428, 455, 641, 642, 705, 676, 9, 642, 111,
+ /* 1670 */ 716, 425, 428, 641, 430, 428, 702, 454, 641, 428,
+ /* 1680 */ 714, 713, 686, 196, 207, 430, 428, 72, 430, 715,
+ /* 1690 */ 428, 436, 430, 686, 195, 716, 686, 197, 411, 430,
+ /* 1700 */ 686, 201, 716, 430, 428, 699, 428, 686, 232, 428,
+ /* 1710 */ 209, 686, 290, 96, 203, 685, 150, 430, 715, 430,
+ /* 1720 */ 42, 224, 430, 86, 319, 686, 190, 686, 194, 428,
+ /* 1730 */ 686, 193, 257, 82, 695, 641, 256, 39, 40, 318,
+ /* 1740 */ 714, 713, 430, 719, 41, 715, 641, 715, 149, 641,
+ /* 1750 */ 686, 185, 4, 641, 707, 679, 287, 642, 709, 422,
+ /* 1760 */ 641, 567, 687, 429, 641, 15, 428, 690, 715, 715,
+ /* 1770 */ 367, 428, 714, 713, 642, 689, 688, 687, 641, 430,
+ /* 1780 */ 641, 716, 703, 641, 430, 147, 287, 686, 188, 701,
+ /* 1790 */ 708, 328, 686, 314, 428, 432, 428, 714, 713, 715,
+ /* 1800 */ 700, 428, 145, 641, 714, 713, 408, 430, 642, 430,
+ /* 1810 */ 676, 9, 642, 428, 430, 686, 313, 686, 312, 715,
+ /* 1820 */ 428, 327, 686, 184, 684, 428, 430, 433, 494, 294,
+ /* 1830 */ 428, 637, 234, 430, 686, 171, 428, 651, 430, 17,
+ /* 1840 */ 641, 686, 170, 430, 715, 641, 686, 183, 293, 430,
+ /* 1850 */ 428, 686, 169, 626, 716, 400, 428, 686, 192, 292,
+ /* 1860 */ 428, 287, 291, 430, 28, 44, 715, 651, 641, 430,
+ /* 1870 */ 641, 686, 191, 430, 715, 641, 428, 686, 168, 428,
+ /* 1880 */ 402, 686, 167, 714, 713, 56, 716, 641, 683, 430,
+ /* 1890 */ 428, 216, 430, 428, 641, 428, 325, 686, 93, 641,
+ /* 1900 */ 686, 166, 716, 430, 641, 428, 430, 428, 430, 640,
+ /* 1910 */ 641, 686, 164, 66, 686, 174, 686, 173, 430, 716,
+ /* 1920 */ 430, 716, 428, 616, 641, 716, 686, 175, 686, 178,
+ /* 1930 */ 641, 229, 419, 214, 641, 430, 228, 415, 428, 716,
+ /* 1940 */ 35, 428, 651, 686, 94, 617, 716, 635, 141, 716,
+ /* 1950 */ 641, 430, 428, 641, 430, 428, 714, 713, 715, 686,
+ /* 1960 */ 177, 139, 686, 176, 641, 430, 108, 641, 430, 641,
+ /* 1970 */ 428, 133, 392, 686, 180, 716, 686, 179, 716, 641,
+ /* 1980 */ 716, 641, 531, 430, 715, 430, 716, 583, 714, 713,
+ /* 1990 */ 389, 686, 165, 686, 70, 393, 641, 716, 248, 716,
+ /* 2000 */ 541, 716, 481, 246, 714, 713, 380, 477, 715, 716,
+ /* 2010 */ 386, 715, 641, 578, 716, 641, 715, 716, 577, 716,
+ /* 2020 */ 330, 714, 713, 714, 713, 275, 641, 714, 713, 641,
+ /* 2030 */ 244, 716, 242, 502, 473, 527, 470, 277, 715, 523,
+ /* 2040 */ 574, 714, 713, 715, 641, 715, 641, 573, 714, 713,
+ /* 2050 */ 310, 714, 713, 236, 568, 549, 269, 322, 572, 554,
+ /* 2060 */ 518, 263, 529, 492, 547, 546, 715, 715, 715, 715,
+ /* 2070 */ 545, 489, 360, 347, 715, 544, 309, 714, 713, 128,
+ /* 2080 */ 714, 713, 714, 713, 442, 715, 715, 521, 714, 713,
+ /* 2090 */ 80, 127, 480, 427, 106, 284, 262, 715, 535, 714,
+ /* 2100 */ 713, 714, 713, 714, 713, 441, 715, 212, 715, 476,
+ /* 2110 */ 126, 714, 713, 443, 354, 648, 714, 713, 24, 714,
+ /* 2120 */ 713, 714, 713, 264, 253, 363, 526, 250, 474, 241,
+ /* 2130 */ 237, 238, 124, 714, 713, 78, 715, 715, 105, 123,
+ /* 2140 */ 715, 121, 715, 715, 715, 84, 513, 155, 104, 348,
+ /* 2150 */ 120, 493, 103, 345, 118, 76, 343, 117, 471, 116,
+ /* 2160 */ 463, 75, 652, 115, 114, 623, 74, 323, 73, 113,
+ /* 2170 */ 23, 451, 20, 449, 101, 445, 100, 112, 439, 520,
+ /* 2180 */ 162, 61, 655, 295, 669, 412, 278, 198, 665, 569,
+ /* 2190 */ 618, 522, 374, 305, 6, 628, 364, 681, 664, 654,
+ /* 2200 */ 260, 361, 211, 556, 409, 71, 296, 566, 560, 559,
+ /* 2210 */ 487, 81, 587, 1150, 46, 586, 1150, 1150, 1150, 1150,
+ /* 2220 */ 550,
+};
+static const YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 4, 81, 82, 83, 84, 85, 86, 87, 4, 58,
+ /* 10 */ 5, 15, 72, 73, 74, 75, 76, 77, 78, 79,
+ /* 20 */ 80, 81, 82, 83, 84, 85, 86, 87, 89, 33,
+ /* 30 */ 34, 26, 34, 28, 72, 73, 74, 75, 42, 77,
+ /* 40 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ /* 50 */ 45, 55, 96, 48, 98, 59, 93, 104, 62, 63,
+ /* 60 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ /* 70 */ 74, 75, 14, 77, 78, 79, 80, 81, 82, 83,
+ /* 80 */ 84, 85, 86, 87, 88, 4, 185, 134, 4, 136,
+ /* 90 */ 137, 111, 96, 35, 4, 104, 15, 101, 104, 103,
+ /* 100 */ 96, 107, 106, 107, 46, 101, 61, 111, 64, 129,
+ /* 110 */ 106, 107, 110, 111, 118, 119, 120, 121, 167, 218,
+ /* 120 */ 219, 123, 118, 42, 83, 84, 85, 86, 87, 104,
+ /* 130 */ 51, 87, 53, 142, 138, 139, 61, 133, 144, 145,
+ /* 140 */ 59, 96, 97, 59, 4, 64, 245, 246, 152, 248,
+ /* 150 */ 154, 155, 156, 109, 110, 111, 112, 113, 114, 115,
+ /* 160 */ 97, 4, 81, 82, 83, 81, 82, 266, 267, 88,
+ /* 170 */ 89, 96, 97, 129, 95, 4, 151, 96, 97, 104,
+ /* 180 */ 96, 91, 101, 4, 103, 104, 128, 106, 107, 4,
+ /* 190 */ 106, 5, 111, 106, 15, 111, 106, 107, 111, 118,
+ /* 200 */ 119, 120, 121, 119, 120, 121, 119, 120, 121, 8,
+ /* 210 */ 4, 10, 26, 12, 28, 134, 61, 136, 137, 61,
+ /* 220 */ 4, 42, 21, 142, 23, 214, 45, 216, 147, 148,
+ /* 230 */ 149, 150, 151, 152, 48, 154, 155, 156, 59, 96,
+ /* 240 */ 161, 97, 41, 64, 177, 44, 106, 107, 104, 48,
+ /* 250 */ 49, 96, 97, 52, 96, 97, 55, 190, 57, 104,
+ /* 260 */ 81, 82, 105, 106, 107, 99, 109, 88, 89, 112,
+ /* 270 */ 113, 114, 101, 86, 87, 96, 97, 106, 107, 212,
+ /* 280 */ 101, 4, 103, 104, 144, 106, 107, 130, 117, 118,
+ /* 290 */ 111, 106, 107, 92, 51, 94, 53, 118, 119, 120,
+ /* 300 */ 121, 177, 96, 118, 135, 124, 125, 126, 177, 140,
+ /* 310 */ 33, 34, 106, 134, 190, 136, 137, 146, 102, 138,
+ /* 320 */ 139, 190, 106, 107, 99, 258, 147, 148, 149, 150,
+ /* 330 */ 99, 152, 131, 154, 155, 156, 212, 152, 95, 62,
+ /* 340 */ 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ /* 350 */ 73, 74, 75, 4, 77, 78, 79, 80, 81, 82,
+ /* 360 */ 83, 84, 85, 86, 87, 4, 177, 166, 4, 194,
+ /* 370 */ 195, 196, 177, 177, 4, 98, 15, 252, 247, 190,
+ /* 380 */ 177, 185, 258, 106, 181, 190, 190, 198, 199, 62,
+ /* 390 */ 63, 64, 65, 190, 269, 68, 69, 70, 71, 72,
+ /* 400 */ 73, 74, 75, 42, 77, 78, 79, 80, 81, 82,
+ /* 410 */ 83, 84, 85, 86, 87, 219, 89, 4, 141, 19,
+ /* 420 */ 59, 232, 233, 109, 24, 64, 112, 113, 114, 29,
+ /* 430 */ 225, 104, 236, 237, 220, 221, 261, 223, 177, 234,
+ /* 440 */ 251, 97, 81, 82, 130, 81, 82, 4, 104, 88,
+ /* 450 */ 89, 190, 4, 258, 4, 106, 107, 96, 97, 198,
+ /* 460 */ 199, 99, 101, 249, 103, 104, 111, 106, 107, 71,
+ /* 470 */ 106, 107, 111, 34, 110, 105, 106, 107, 151, 118,
+ /* 480 */ 119, 120, 121, 119, 120, 220, 221, 123, 223, 125,
+ /* 490 */ 19, 43, 33, 34, 96, 134, 97, 136, 137, 40,
+ /* 500 */ 29, 152, 96, 64, 158, 244, 160, 83, 147, 96,
+ /* 510 */ 149, 150, 251, 152, 101, 154, 155, 156, 97, 106,
+ /* 520 */ 107, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 530 */ 71, 72, 73, 74, 75, 97, 77, 78, 79, 80,
+ /* 540 */ 81, 82, 83, 84, 85, 86, 87, 9, 100, 106,
+ /* 550 */ 107, 101, 205, 206, 106, 107, 106, 107, 20, 135,
+ /* 560 */ 213, 118, 123, 104, 140, 123, 4, 190, 129, 4,
+ /* 570 */ 96, 33, 34, 64, 65, 198, 133, 68, 69, 70,
+ /* 580 */ 71, 72, 73, 74, 75, 143, 77, 78, 79, 80,
+ /* 590 */ 81, 82, 83, 84, 85, 86, 87, 33, 34, 55,
+ /* 600 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ /* 610 */ 72, 73, 74, 75, 164, 77, 78, 79, 80, 81,
+ /* 620 */ 82, 83, 84, 85, 86, 87, 62, 63, 64, 65,
+ /* 630 */ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ /* 640 */ 4, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ /* 650 */ 86, 87, 33, 34, 110, 77, 78, 79, 80, 81,
+ /* 660 */ 82, 83, 84, 85, 86, 87, 177, 177, 106, 107,
+ /* 670 */ 50, 106, 182, 108, 54, 104, 186, 187, 116, 190,
+ /* 680 */ 190, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 690 */ 71, 72, 73, 74, 75, 12, 77, 78, 79, 80,
+ /* 700 */ 81, 82, 83, 84, 85, 86, 87, 62, 63, 64,
+ /* 710 */ 65, 98, 23, 68, 69, 70, 71, 72, 73, 74,
+ /* 720 */ 75, 96, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 730 */ 85, 86, 87, 113, 89, 188, 100, 101, 191, 192,
+ /* 740 */ 193, 97, 106, 107, 55, 62, 63, 64, 65, 104,
+ /* 750 */ 98, 68, 69, 70, 71, 72, 73, 74, 75, 30,
+ /* 760 */ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ /* 770 */ 87, 96, 89, 38, 4, 97, 177, 4, 89, 4,
+ /* 780 */ 23, 161, 104, 104, 4, 170, 171, 172, 173, 190,
+ /* 790 */ 194, 195, 196, 64, 195, 196, 151, 62, 63, 64,
+ /* 800 */ 65, 122, 4, 68, 69, 70, 71, 72, 73, 74,
+ /* 810 */ 75, 179, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 820 */ 85, 86, 87, 4, 89, 55, 124, 125, 126, 62,
+ /* 830 */ 63, 64, 65, 4, 15, 68, 69, 70, 71, 72,
+ /* 840 */ 73, 74, 75, 177, 77, 78, 79, 80, 81, 82,
+ /* 850 */ 83, 84, 85, 86, 87, 97, 190, 261, 83, 260,
+ /* 860 */ 261, 42, 104, 4, 9, 98, 96, 97, 169, 119,
+ /* 870 */ 120, 101, 0, 174, 55, 20, 106, 107, 59, 106,
+ /* 880 */ 107, 106, 107, 64, 185, 97, 106, 107, 118, 257,
+ /* 890 */ 185, 118, 104, 118, 96, 33, 34, 25, 118, 101,
+ /* 900 */ 81, 82, 97, 133, 106, 107, 4, 88, 138, 139,
+ /* 910 */ 4, 214, 4, 216, 4, 96, 118, 218, 219, 146,
+ /* 920 */ 101, 96, 103, 218, 219, 106, 107, 152, 66, 67,
+ /* 930 */ 111, 133, 124, 125, 126, 106, 107, 118, 119, 120,
+ /* 940 */ 121, 177, 144, 145, 245, 246, 177, 248, 185, 185,
+ /* 950 */ 245, 246, 104, 248, 190, 186, 187, 138, 139, 190,
+ /* 960 */ 101, 89, 198, 199, 97, 106, 107, 97, 81, 82,
+ /* 970 */ 271, 152, 267, 154, 155, 156, 185, 118, 62, 63,
+ /* 980 */ 64, 65, 219, 219, 68, 69, 70, 71, 72, 73,
+ /* 990 */ 74, 75, 97, 77, 78, 79, 80, 81, 82, 83,
+ /* 1000 */ 84, 85, 86, 87, 158, 146, 119, 120, 106, 107,
+ /* 1010 */ 219, 101, 106, 107, 106, 251, 106, 107, 272, 273,
+ /* 1020 */ 62, 63, 64, 65, 118, 117, 68, 69, 70, 71,
+ /* 1030 */ 72, 73, 74, 75, 97, 77, 78, 79, 80, 81,
+ /* 1040 */ 82, 83, 84, 85, 86, 87, 144, 62, 63, 64,
+ /* 1050 */ 65, 4, 146, 68, 69, 70, 71, 72, 73, 74,
+ /* 1060 */ 75, 177, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 1070 */ 85, 86, 87, 163, 190, 159, 191, 192, 193, 195,
+ /* 1080 */ 196, 97, 97, 62, 63, 64, 65, 97, 104, 68,
+ /* 1090 */ 69, 70, 71, 72, 73, 74, 75, 104, 77, 78,
+ /* 1100 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 185,
+ /* 1110 */ 172, 173, 13, 62, 63, 64, 65, 159, 97, 68,
+ /* 1120 */ 69, 70, 71, 72, 73, 74, 75, 177, 77, 78,
+ /* 1130 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 97,
+ /* 1140 */ 190, 185, 104, 219, 260, 261, 104, 13, 97, 62,
+ /* 1150 */ 63, 64, 65, 106, 107, 68, 69, 70, 71, 72,
+ /* 1160 */ 73, 74, 75, 116, 77, 78, 79, 80, 81, 82,
+ /* 1170 */ 83, 84, 85, 86, 87, 219, 97, 138, 139, 62,
+ /* 1180 */ 63, 64, 65, 104, 97, 68, 69, 70, 71, 72,
+ /* 1190 */ 73, 74, 75, 243, 77, 78, 79, 80, 81, 82,
+ /* 1200 */ 83, 84, 85, 86, 87, 185, 55, 4, 197, 25,
+ /* 1210 */ 96, 62, 63, 64, 65, 98, 205, 68, 69, 70,
+ /* 1220 */ 71, 72, 73, 74, 75, 30, 77, 78, 79, 80,
+ /* 1230 */ 81, 82, 83, 84, 85, 86, 87, 4, 89, 219,
+ /* 1240 */ 89, 4, 62, 63, 64, 65, 144, 13, 68, 69,
+ /* 1250 */ 70, 71, 72, 73, 74, 75, 97, 77, 78, 79,
+ /* 1260 */ 80, 81, 82, 83, 84, 85, 86, 87, 4, 89,
+ /* 1270 */ 97, 97, 104, 89, 62, 63, 64, 65, 104, 15,
+ /* 1280 */ 68, 69, 70, 71, 72, 73, 74, 75, 191, 77,
+ /* 1290 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ /* 1300 */ 177, 177, 177, 177, 177, 4, 42, 185, 185, 106,
+ /* 1310 */ 186, 187, 97, 190, 190, 190, 190, 190, 177, 104,
+ /* 1320 */ 117, 198, 199, 59, 198, 199, 99, 177, 64, 4,
+ /* 1330 */ 99, 190, 235, 209, 83, 211, 96, 100, 101, 106,
+ /* 1340 */ 190, 219, 219, 106, 107, 81, 82, 4, 198, 199,
+ /* 1350 */ 117, 4, 88, 191, 191, 232, 233, 97, 232, 233,
+ /* 1360 */ 96, 97, 15, 236, 237, 101, 177, 103, 243, 96,
+ /* 1370 */ 106, 107, 4, 177, 251, 111, 4, 251, 177, 190,
+ /* 1380 */ 4, 191, 118, 119, 120, 121, 190, 198, 199, 42,
+ /* 1390 */ 4, 190, 7, 135, 4, 201, 11, 235, 235, 198,
+ /* 1400 */ 199, 251, 101, 97, 254, 201, 59, 106, 107, 177,
+ /* 1410 */ 97, 64, 4, 181, 252, 97, 152, 32, 154, 155,
+ /* 1420 */ 156, 232, 190, 177, 17, 235, 101, 181, 81, 82,
+ /* 1430 */ 38, 106, 107, 232, 4, 88, 190, 4, 177, 243,
+ /* 1440 */ 251, 98, 4, 96, 97, 15, 252, 177, 101, 106,
+ /* 1450 */ 103, 190, 251, 106, 107, 4, 252, 132, 111, 4,
+ /* 1460 */ 190, 96, 6, 162, 4, 118, 119, 120, 121, 101,
+ /* 1470 */ 38, 96, 42, 101, 106, 107, 97, 101, 106, 107,
+ /* 1480 */ 96, 38, 106, 107, 141, 96, 118, 101, 115, 59,
+ /* 1490 */ 118, 101, 106, 107, 64, 4, 106, 107, 237, 152,
+ /* 1500 */ 177, 154, 155, 156, 118, 96, 177, 177, 118, 133,
+ /* 1510 */ 177, 81, 82, 190, 106, 107, 4, 177, 88, 190,
+ /* 1520 */ 190, 198, 199, 190, 129, 4, 96, 15, 198, 199,
+ /* 1530 */ 190, 101, 64, 103, 101, 98, 106, 107, 103, 106,
+ /* 1540 */ 107, 111, 123, 12, 106, 107, 276, 142, 118, 119,
+ /* 1550 */ 120, 121, 101, 128, 42, 177, 101, 106, 107, 181,
+ /* 1560 */ 71, 106, 107, 71, 177, 157, 106, 107, 190, 153,
+ /* 1570 */ 177, 59, 89, 118, 251, 139, 64, 190, 4, 146,
+ /* 1580 */ 22, 251, 152, 190, 154, 155, 156, 47, 158, 177,
+ /* 1590 */ 152, 100, 89, 81, 82, 39, 123, 106, 107, 177,
+ /* 1600 */ 88, 141, 190, 39, 177, 276, 161, 96, 96, 97,
+ /* 1610 */ 198, 199, 190, 101, 104, 103, 165, 190, 106, 107,
+ /* 1620 */ 198, 199, 143, 111, 37, 198, 199, 106, 107, 95,
+ /* 1630 */ 118, 119, 120, 121, 96, 63, 64, 65, 4, 118,
+ /* 1640 */ 68, 69, 70, 71, 72, 73, 74, 75, 103, 77,
+ /* 1650 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ /* 1660 */ 4, 177, 97, 251, 152, 91, 154, 155, 156, 93,
+ /* 1670 */ 4, 15, 177, 251, 190, 177, 177, 97, 251, 177,
+ /* 1680 */ 106, 107, 198, 199, 238, 190, 177, 95, 190, 190,
+ /* 1690 */ 177, 36, 190, 198, 199, 4, 198, 199, 42, 190,
+ /* 1700 */ 198, 199, 4, 190, 177, 177, 177, 198, 199, 177,
+ /* 1710 */ 252, 198, 199, 189, 273, 59, 90, 190, 190, 190,
+ /* 1720 */ 64, 204, 190, 204, 275, 198, 199, 198, 199, 177,
+ /* 1730 */ 198, 199, 177, 180, 177, 251, 181, 81, 82, 275,
+ /* 1740 */ 106, 107, 190, 176, 88, 190, 251, 190, 178, 251,
+ /* 1750 */ 198, 199, 96, 251, 49, 177, 177, 101, 176, 103,
+ /* 1760 */ 251, 127, 106, 107, 251, 104, 177, 111, 190, 190,
+ /* 1770 */ 60, 177, 106, 107, 118, 119, 120, 121, 251, 190,
+ /* 1780 */ 251, 4, 91, 251, 190, 178, 177, 198, 199, 91,
+ /* 1790 */ 176, 212, 198, 199, 177, 183, 177, 106, 107, 190,
+ /* 1800 */ 184, 177, 56, 251, 106, 107, 177, 190, 152, 190,
+ /* 1810 */ 154, 155, 156, 177, 190, 198, 199, 198, 199, 190,
+ /* 1820 */ 177, 212, 198, 199, 221, 177, 190, 176, 162, 227,
+ /* 1830 */ 177, 177, 138, 190, 198, 199, 177, 258, 190, 151,
+ /* 1840 */ 251, 198, 199, 190, 190, 251, 198, 199, 228, 190,
+ /* 1850 */ 177, 198, 199, 177, 4, 148, 177, 198, 199, 229,
+ /* 1860 */ 177, 177, 230, 190, 149, 252, 190, 258, 251, 190,
+ /* 1870 */ 251, 198, 199, 190, 190, 251, 177, 198, 199, 177,
+ /* 1880 */ 147, 198, 199, 106, 107, 150, 4, 251, 231, 190,
+ /* 1890 */ 177, 87, 190, 177, 251, 177, 212, 198, 199, 251,
+ /* 1900 */ 198, 199, 4, 190, 251, 177, 190, 177, 190, 64,
+ /* 1910 */ 251, 198, 199, 96, 198, 199, 198, 199, 190, 4,
+ /* 1920 */ 190, 4, 177, 146, 251, 4, 198, 199, 198, 199,
+ /* 1930 */ 251, 259, 203, 87, 251, 190, 255, 203, 177, 4,
+ /* 1940 */ 158, 177, 258, 198, 199, 177, 4, 241, 99, 4,
+ /* 1950 */ 251, 190, 177, 251, 190, 177, 106, 107, 190, 198,
+ /* 1960 */ 199, 241, 198, 199, 251, 190, 99, 251, 190, 251,
+ /* 1970 */ 177, 177, 177, 198, 199, 4, 198, 199, 4, 251,
+ /* 1980 */ 4, 251, 132, 190, 190, 190, 4, 200, 106, 107,
+ /* 1990 */ 223, 198, 199, 198, 199, 177, 251, 4, 177, 4,
+ /* 2000 */ 118, 4, 181, 177, 106, 107, 123, 181, 190, 4,
+ /* 2010 */ 139, 190, 251, 200, 4, 251, 190, 4, 208, 4,
+ /* 2020 */ 31, 106, 107, 106, 107, 177, 251, 106, 107, 251,
+ /* 2030 */ 177, 4, 177, 118, 181, 118, 181, 200, 190, 118,
+ /* 2040 */ 202, 106, 107, 190, 251, 190, 251, 122, 106, 107,
+ /* 2050 */ 203, 106, 107, 177, 177, 177, 177, 181, 200, 208,
+ /* 2060 */ 118, 177, 164, 118, 200, 200, 190, 190, 190, 190,
+ /* 2070 */ 200, 100, 177, 177, 190, 200, 203, 106, 107, 99,
+ /* 2080 */ 106, 107, 106, 107, 177, 190, 190, 152, 106, 107,
+ /* 2090 */ 180, 99, 118, 177, 180, 177, 264, 190, 241, 106,
+ /* 2100 */ 107, 106, 107, 106, 107, 100, 190, 241, 190, 133,
+ /* 2110 */ 99, 106, 107, 118, 27, 100, 106, 107, 158, 106,
+ /* 2120 */ 107, 106, 107, 177, 177, 265, 227, 177, 146, 177,
+ /* 2130 */ 177, 177, 99, 106, 107, 215, 190, 190, 62, 99,
+ /* 2140 */ 190, 99, 190, 190, 190, 96, 215, 250, 180, 241,
+ /* 2150 */ 99, 227, 180, 241, 99, 217, 60, 99, 165, 99,
+ /* 2160 */ 163, 217, 152, 99, 99, 152, 217, 241, 217, 99,
+ /* 2170 */ 268, 18, 268, 241, 99, 241, 99, 99, 16, 152,
+ /* 2180 */ 224, 270, 201, 226, 261, 256, 201, 210, 261, 206,
+ /* 2190 */ 242, 227, 202, 175, 224, 240, 263, 191, 191, 191,
+ /* 2200 */ 242, 242, 262, 191, 216, 239, 222, 207, 207, 207,
+ /* 2210 */ 274, 55, 198, 277, 253, 198, 277, 277, 277, 277,
+ /* 2220 */ 211,
+};
+#define YY_SHIFT_USE_DFLT (-81)
+#define YY_SHIFT_COUNT (434)
+#define YY_SHIFT_MIN (-80)
+#define YY_SHIFT_MAX (2162)
+static const short yy_shift_ofst[] = {
+ /* 0 */ 1184, -4, 201, 1151, 819, 1512, 1512, 689, 361, 1430,
+ /* 10 */ 1656, 1656, 770, 364, 364, 157, 81, 179, 1347, 1264,
+ /* 20 */ 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656,
+ /* 30 */ 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656,
+ /* 40 */ 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656,
+ /* 50 */ 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 370, 798,
+ /* 60 */ 181, 370, 2010, 2010, 2010, 2010, 2010, 887, 887, 565,
+ /* 70 */ 277, 4, 1455, 1451, 1433, 1376, 1390, 1386, 1372, 1368,
+ /* 80 */ 1325, 448, 1237, 2013, 2013, 2027, 439, 2013, 2015, 2010,
+ /* 90 */ 565, 1039, 538, 538, 735, 84, 44, 171, 859, 775,
+ /* 100 */ 906, 773, 910, 636, 1301, 5, 450, 5, 443, 413,
+ /* 110 */ 185, 2005, 1995, 1997, 1993, 1982, 1976, 1974, 1971, 1945,
+ /* 120 */ 1666, 1942, 1935, 1921, 1917, 1915, 1898, 1850, 1491, 1882,
+ /* 130 */ 1047, 1634, 1521, 902, 140, 1343, 1343, 1777, 1460, 1343,
+ /* 140 */ 1438, 780, 1408, 349, 562, 216, 620, 1698, 1691, 1574,
+ /* 150 */ 90, 829, 829, 829, 872, 544, 2156, 2156, 2156, 2156,
+ /* 160 */ 2156, -81, -81, 459, 619, 619, 619, 619, 619, 619,
+ /* 170 */ 619, 619, 619, 645, 327, 683, 1180, 1149, 1117, 1087,
+ /* 180 */ 1051, 1021, 985, 958, 916, 767, 1212, 1572, 509, 509,
+ /* 190 */ -60, -38, -38, -38, -38, -38, 578, -80, 314, 87,
+ /* 200 */ 87, 41, 155, 75, 58, 58, 58, -6, 186, 862,
+ /* 210 */ -47, 808, 1385, 1233, 1203, 206, 908, 424, 400, 25,
+ /* 220 */ 729, 729, 679, 1215, -2, 855, 729, 442, 346, 855,
+ /* 230 */ 750, 750, 187, -9, 169, 2162, 2078, 2077, 2075, 2153,
+ /* 240 */ 2153, 2070, 2065, 2096, 2064, 2096, 2060, 2096, 2058, 2096,
+ /* 250 */ 2055, 1710, 1688, 2051, 1710, 2076, 2049, 2042, 2040, 2076,
+ /* 260 */ 1688, 2033, 1960, 2087, 2011, 1710, 1992, 1710, 1980, 1817,
+ /* 270 */ 1883, 1883, 1883, 1883, 1989, 1817, 1883, 1925, 1883, 1989,
+ /* 280 */ 1883, 1883, 1871, 1867, 1849, 1782, 1817, 1846, 1817, 1845,
+ /* 290 */ 1804, 1735, 1733, 1715, 1707, 1688, 1694, 1746, 1661, 1710,
+ /* 300 */ 1705, 1705, 1626, 1626, 1626, 1626, -81, -81, -81, -81,
+ /* 310 */ -81, -81, -81, -81, -81, -81, 564, 79, 158, 45,
+ /* 320 */ 702, 243, -49, 398, 1174, 1079, 1042, 984, 788, 2,
+ /* 330 */ 471, -20, 758, 678, 344, 144, -44, 1655, 1587, 1576,
+ /* 340 */ 1592, 1580, 1565, 1545, 1538, 1479, 1534, 1511, 1473, 1445,
+ /* 350 */ 1564, 1510, 1556, 1540, 1558, 1503, 1483, 1436, 1416, 1492,
+ /* 360 */ 1489, 1425, 1405, 1531, 1419, 1437, 1435, 1468, 1395, 1373,
+ /* 370 */ 1409, 1443, 1389, 1384, 1379, 1375, 1432, 1456, 1365, 1392,
+ /* 380 */ 1407, 1318, 1313, 1306, 1168, 1258, 1273, 1260, 1240, 1168,
+ /* 390 */ 1251, 1231, 1227, 1102, 1173, 1159, 1195, 1234, 1114, 993,
+ /* 400 */ 1134, 1038, 1099, 993, 990, 937, 846, 895, 870, 848,
+ /* 410 */ 867, 825, 757, 805, 675, 652, 571, 644, 625, 613,
+ /* 420 */ 571, 438, 474, 421, 399, 406, 355, 362, 231, 225,
+ /* 430 */ 166, 143, 63, -37, -61,
+};
+#define YY_REDUCE_USE_DFLT (-100)
+#define YY_REDUCE_COUNT (315)
+#define YY_REDUCE_MIN (-99)
+#define YY_REDUCE_MAX (2018)
+static const short yy_reduce_ofst[] = {
+ /* 0 */ 615, 1123, 699, -99, 764, 1126, 189, 705, 1201, 1150,
+ /* 10 */ 1189, 261, 196, 884, 599, 1124, 1795, 1793, 1778, 1775,
+ /* 20 */ 1764, 1761, 1745, 1730, 1728, 1718, 1716, 1713, 1702, 1699,
+ /* 30 */ 1683, 1679, 1673, 1659, 1653, 1648, 1643, 1636, 1624, 1619,
+ /* 40 */ 1617, 1594, 1589, 1552, 1532, 1529, 1527, 1513, 1509, 1502,
+ /* 50 */ 1498, 1495, 1484, 1427, 1422, 1412, 1330, 1323, 490, 1127,
+ /* 60 */ 214, 769, 1684, 1609, 1579, 124, 67, 596, 175, 547,
+ /* 70 */ 1162, 1261, 1876, 1855, 1853, 1826, 1821, 1555, 1378, 1246,
+ /* 80 */ 1232, 1329, 203, 1196, 1125, 131, 347, 950, 1270, 195,
+ /* 90 */ 885, 265, 1204, 1194, 125, 377, 1011, 1954, 1953, 1916,
+ /* 100 */ 1654, 1654, 1952, 1950, 1947, 697, 1946, 11, 1654, 1918,
+ /* 110 */ 1916, 1907, 1654, 1654, 1654, 1654, 1654, 1654, 1654, 1896,
+ /* 120 */ 1654, 1654, 1895, 1654, 1654, 1884, 1654, 1654, 1654, 1879,
+ /* 130 */ 1878, 1877, 1848, 1818, 1794, 1190, 1163, 1768, 1333, 1097,
+ /* 140 */ 1676, 1654, 1629, 1578, 1557, 1528, 632, 1499, 1393, 1387,
+ /* 150 */ 1340, 1141, 666, 489, 938, 1122, 1020, 956, 924, 791,
+ /* 160 */ 763, 746, 205, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ /* 170 */ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ /* 180 */ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ /* 190 */ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 2009, 2017,
+ /* 200 */ 2014, 1458, 1936, 1936, 2002, 2001, 2000, 1966, 1988, 1961,
+ /* 210 */ 1984, 1933, 1940, 2012, 2008, 2007, 2006, 1970, 2018, 1964,
+ /* 220 */ 1959, 1958, 1990, 1977, 1983, 1985, 1948, 1955, 1929, 1981,
+ /* 230 */ 1927, 1923, 1458, 1957, 1956, 1911, 1857, 1934, 1932, 1904,
+ /* 240 */ 1902, 1926, 1857, 1951, 1857, 1949, 1857, 1944, 1857, 1938,
+ /* 250 */ 1912, 1972, 1924, 1908, 1968, 1931, 1897, 1857, 1857, 1920,
+ /* 260 */ 1899, 1857, 1860, 1832, 1866, 1914, 1857, 1910, 1857, 1873,
+ /* 270 */ 1875, 1870, 1865, 1864, 1851, 1847, 1858, 1838, 1837, 1810,
+ /* 280 */ 1813, 1787, 1767, 1720, 1706, 1681, 1734, 1672, 1729, 1613,
+ /* 290 */ 1458, 1657, 1632, 1630, 1620, 1602, 1603, 1616, 1612, 1553,
+ /* 300 */ 1607, 1570, 1651, 1614, 1582, 1567, 1464, 1449, 1441, 1519,
+ /* 310 */ 1517, 1446, 1458, 1458, 1458, 1524,
+};
+static const YYACTIONTYPE yy_default[] = {
+ /* 0 */ 729, 1037, 1142, 1142, 1026, 1026, 1026, 1142, 1026, 1026,
+ /* 10 */ 1026, 1026, 900, 1148, 1148, 1148, 1026, 1026, 1026, 1026,
+ /* 20 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
+ /* 30 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
+ /* 40 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
+ /* 50 */ 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1148, 894,
+ /* 60 */ 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 774,
+ /* 70 */ 890, 900, 1148, 1148, 1148, 1148, 1148, 962, 949, 940,
+ /* 80 */ 1148, 1148, 1148, 972, 972, 955, 842, 972, 1148, 1148,
+ /* 90 */ 1148, 1148, 928, 928, 1027, 1148, 766, 1112, 1117, 1013,
+ /* 100 */ 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 901, 1148,
+ /* 110 */ 1013, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148,
+ /* 120 */ 1148, 963, 956, 950, 941, 1148, 1148, 1148, 1148, 1148,
+ /* 130 */ 1148, 1148, 1148, 1148, 1148, 890, 890, 1148, 1148, 890,
+ /* 140 */ 1148, 1148, 1148, 1014, 1148, 1148, 763, 1148, 1148, 1148,
+ /* 150 */ 735, 1058, 1148, 1148, 729, 1142, 1142, 1142, 1142, 1142,
+ /* 160 */ 1142, 1135, 880, 935, 906, 945, 933, 937, 1038, 1031,
+ /* 170 */ 1032, 1030, 936, 1027, 1027, 1027, 1027, 1027, 1027, 1027,
+ /* 180 */ 1027, 1027, 1027, 1027, 1027, 1027, 1027, 988, 1000, 987,
+ /* 190 */ 995, 1004, 1015, 999, 996, 990, 989, 991, 1148, 1148,
+ /* 200 */ 1148, 992, 1148, 1148, 1148, 1148, 1148, 893, 1148, 1148,
+ /* 210 */ 864, 1148, 1086, 1148, 1148, 776, 1148, 878, 738, 944,
+ /* 220 */ 918, 918, 809, 833, 798, 928, 918, 908, 1033, 928,
+ /* 230 */ 1148, 1148, 993, 891, 878, 1126, 909, 909, 909, 1111,
+ /* 240 */ 1111, 909, 909, 855, 909, 855, 909, 855, 909, 855,
+ /* 250 */ 909, 760, 944, 909, 760, 846, 968, 909, 909, 846,
+ /* 260 */ 944, 909, 1093, 1091, 909, 760, 909, 760, 909, 1046,
+ /* 270 */ 844, 844, 844, 844, 825, 1046, 844, 809, 844, 825,
+ /* 280 */ 844, 844, 1148, 909, 909, 1148, 1046, 1052, 1046, 1027,
+ /* 290 */ 994, 934, 922, 932, 929, 944, 1148, 757, 828, 760,
+ /* 300 */ 746, 746, 734, 734, 734, 734, 1139, 1139, 1135, 811,
+ /* 310 */ 811, 896, 1003, 1002, 1001, 785, 1039, 1148, 1148, 1148,
+ /* 320 */ 1148, 1148, 1148, 1060, 1148, 1148, 1148, 1148, 1148, 1148,
+ /* 330 */ 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 730, 1148,
+ /* 340 */ 1148, 1148, 1148, 1148, 1129, 1148, 1148, 1148, 1148, 1148,
+ /* 350 */ 1148, 1090, 1089, 1148, 1148, 1148, 1148, 1148, 1148, 1148,
+ /* 360 */ 1148, 1148, 1148, 1078, 1148, 1148, 1148, 1148, 1148, 1148,
+ /* 370 */ 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148,
+ /* 380 */ 1148, 1148, 1148, 1148, 867, 869, 1148, 1148, 1148, 868,
+ /* 390 */ 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 930,
+ /* 400 */ 1148, 923, 1148, 1036, 1148, 1017, 1025, 1148, 1148, 1148,
+ /* 410 */ 1148, 1148, 1016, 1148, 1148, 1148, 1144, 1148, 1148, 1148,
+ /* 420 */ 1143, 1148, 1148, 1148, 1148, 1148, 1028, 980, 1148, 979,
+ /* 430 */ 978, 769, 1148, 744, 1148, 726, 731, 1128, 1125, 1127,
+ /* 440 */ 1122, 1123, 1121, 1124, 1120, 1118, 1119, 1116, 1114, 1113,
+ /* 450 */ 1115, 1110, 1106, 1066, 1064, 1062, 1071, 1070, 1069, 1068,
+ /* 460 */ 1067, 1063, 1061, 1065, 1059, 959, 947, 938, 862, 1105,
+ /* 470 */ 1103, 1104, 1057, 1055, 1056, 861, 860, 859, 854, 853,
+ /* 480 */ 852, 851, 1132, 1141, 1140, 1138, 1137, 1136, 1130, 1131,
+ /* 490 */ 1044, 1043, 1041, 1040, 1042, 762, 1082, 1085, 1084, 1083,
+ /* 500 */ 1088, 1087, 1080, 1092, 1097, 1096, 1101, 1100, 1099, 1098,
+ /* 510 */ 1095, 1077, 967, 966, 964, 969, 961, 960, 965, 952,
+ /* 520 */ 958, 957, 948, 951, 847, 943, 939, 942, 863, 1081,
+ /* 530 */ 858, 857, 856, 761, 756, 911, 755, 754, 765, 831,
+ /* 540 */ 832, 840, 843, 838, 841, 837, 836, 835, 839, 834,
+ /* 550 */ 830, 768, 767, 775, 824, 802, 800, 799, 803, 816,
+ /* 560 */ 815, 822, 821, 820, 819, 818, 814, 817, 813, 812,
+ /* 570 */ 804, 797, 796, 810, 795, 827, 826, 823, 794, 850,
+ /* 580 */ 849, 848, 845, 793, 792, 791, 790, 789, 788, 986,
+ /* 590 */ 985, 1006, 977, 865, 872, 871, 870, 874, 875, 885,
+ /* 600 */ 883, 882, 881, 917, 916, 915, 914, 913, 912, 905,
+ /* 610 */ 903, 899, 898, 904, 902, 920, 921, 919, 897, 889,
+ /* 620 */ 887, 888, 886, 974, 971, 973, 970, 907, 895, 892,
+ /* 630 */ 879, 925, 924, 1029, 1018, 1008, 1019, 910, 1007, 1005,
+ /* 640 */ 1028, 1025, 1020, 1102, 1024, 1012, 1011, 1010, 1147, 1145,
+ /* 650 */ 1146, 1049, 1051, 1054, 1053, 1050, 927, 926, 1048, 1047,
+ /* 660 */ 1009, 984, 781, 779, 780, 1074, 1073, 1076, 1075, 1072,
+ /* 670 */ 783, 782, 778, 777, 998, 997, 982, 1021, 1022, 981,
+ /* 680 */ 1023, 983, 770, 873, 866, 976, 975, 808, 807, 806,
+ /* 690 */ 805, 877, 876, 787, 801, 786, 784, 764, 759, 758,
+ /* 700 */ 753, 751, 748, 750, 747, 752, 749, 745, 743, 742,
+ /* 710 */ 741, 740, 739, 773, 772, 771, 769, 737, 736, 733,
+ /* 720 */ 732, 728, 727, 725,
+};
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+ 0, /* $ => nothing */
+ 0, /* ILLEGAL => nothing */
+ 0, /* COMMENT => nothing */
+ 0, /* SPACE => nothing */
+ 0, /* ID => nothing */
+ 4, /* ABORT => ID */
+ 4, /* ACTION => ID */
+ 4, /* AFTER => ID */
+ 4, /* ANALYZE => ID */
+ 4, /* ASC => ID */
+ 4, /* ATTACH => ID */
+ 4, /* BEFORE => ID */
+ 4, /* BEGIN => ID */
+ 4, /* BY => ID */
+ 4, /* CASCADE => ID */
+ 4, /* CAST => ID */
+ 4, /* COLUMNKW => ID */
+ 4, /* CONFLICT => ID */
+ 4, /* DATABASE => ID */
+ 4, /* DEFERRED => ID */
+ 4, /* DESC => ID */
+ 4, /* DETACH => ID */
+ 4, /* EACH => ID */
+ 4, /* END => ID */
+ 4, /* EXCLUSIVE => ID */
+ 4, /* EXPLAIN => ID */
+ 4, /* FAIL => ID */
+ 4, /* FOR => ID */
+ 4, /* IGNORE => ID */
+ 4, /* IMMEDIATE => ID */
+ 4, /* INDEXED => ID */
+ 4, /* INITIALLY => ID */
+ 4, /* INSTEAD => ID */
+ 4, /* LIKE_KW => ID */
+ 4, /* MATCH => ID */
+ 4, /* NO => ID */
+ 4, /* PLAN => ID */
+ 4, /* QUERY => ID */
+ 4, /* KEY => ID */
+ 4, /* OF => ID */
+ 4, /* OFFSET => ID */
+ 4, /* PRAGMA => ID */
+ 4, /* RAISE => ID */
+ 4, /* RECURSIVE => ID */
+ 4, /* RELEASE => ID */
+ 4, /* REPLACE => ID */
+ 4, /* RESTRICT => ID */
+ 4, /* ROW => ID */
+ 4, /* ROLLBACK => ID */
+ 4, /* SAVEPOINT => ID */
+ 4, /* TEMP => ID */
+ 4, /* TRIGGER => ID */
+ 4, /* VACUUM => ID */
+ 4, /* VIEW => ID */
+ 4, /* VIRTUAL => ID */
+ 4, /* WITH => ID */
+ 4, /* WITHOUT => ID */
+ 4, /* REINDEX => ID */
+ 4, /* RENAME => ID */
+ 4, /* CTIME_KW => ID */
+ 4, /* IF => ID */
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ YYACTIONTYPE stateno; /* The state-number */
+ YYCODETYPE major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+ QList<Token*>* tokens = nullptr;
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+ int yyidxMax; /* Maximum value of yyidx */
+#endif
+ int yyerrcnt; /* Shifts left before out of the error */
+ sqlite3_parseARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+void *sqlite3_parseCopyParserState(void* other)
+{
+ yyParser *pParser;
+ yyParser *otherParser = (yyParser*)other;
+
+ // Copy parser
+ pParser = (yyParser*)malloc((size_t)sizeof(yyParser));
+ memcpy(pParser, other, (size_t)sizeof(yyParser));
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = malloc((size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)other)->yystack, (size_t)stackSize);
+#endif
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(otherParser->yystack[i].tokens);
+ }
+
+ return pParser;
+}
+
+void sqlite3_parseAddToken(void* other, Token* token)
+{
+ yyParser *otherParser = (yyParser*)other;
+ if (otherParser->yyidx < 0)
+ return; // Nothing on stack yet. Might happen when parsing just whitespaces, nothing else.
+
+ otherParser->yystack[otherParser->yyidx].tokens->append(token);
+}
+
+void sqlite3_parseRestoreParserState(void* saved, void* target)
+{
+ yyParser *pParser = (yyParser*)target;
+ yyParser *savedParser = (yyParser*)saved;
+
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+ memcpy(pParser, saved, (size_t)sizeof(yyParser));
+
+ for (int i = 0; i <= savedParser->yyidx; i++)
+ {
+ pParser->yystack[i].tokens = new QList<Token*>();
+ *(pParser->yystack[i].tokens) = *(savedParser->yystack[i].tokens);
+ }
+
+#if YYSTACKDEPTH<=0
+ // Copy stack
+ int stackSize = sizeof(yyStackEntry) * pParser->yystksz;
+ pParser->yystack = relloc(pParser->yystack, (size_t)stackSize);
+ memcpy(pParser->yystack, ((yyParser*)saved)->yystack, (size_t)stackSize);
+#endif
+}
+
+void sqlite3_parseFreeSavedState(void* other)
+{
+ yyParser *pParser = (yyParser*)other;
+ for (int i = 0; i <= pParser->yyidx; i++)
+ delete pParser->yystack[i].tokens;
+
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ free(other);
+}
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void sqlite3_parseTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *const yyTokenName[] = {
+ "$", "ILLEGAL", "COMMENT", "SPACE",
+ "ID", "ABORT", "ACTION", "AFTER",
+ "ANALYZE", "ASC", "ATTACH", "BEFORE",
+ "BEGIN", "BY", "CASCADE", "CAST",
+ "COLUMNKW", "CONFLICT", "DATABASE", "DEFERRED",
+ "DESC", "DETACH", "EACH", "END",
+ "EXCLUSIVE", "EXPLAIN", "FAIL", "FOR",
+ "IGNORE", "IMMEDIATE", "INDEXED", "INITIALLY",
+ "INSTEAD", "LIKE_KW", "MATCH", "NO",
+ "PLAN", "QUERY", "KEY", "OF",
+ "OFFSET", "PRAGMA", "RAISE", "RECURSIVE",
+ "RELEASE", "REPLACE", "RESTRICT", "ROW",
+ "ROLLBACK", "SAVEPOINT", "TEMP", "TRIGGER",
+ "VACUUM", "VIEW", "VIRTUAL", "WITH",
+ "WITHOUT", "REINDEX", "RENAME", "CTIME_KW",
+ "IF", "ANY", "OR", "AND",
+ "NOT", "IS", "BETWEEN", "IN",
+ "ISNULL", "NOTNULL", "NE", "EQ",
+ "GT", "LE", "LT", "GE",
+ "ESCAPE", "BITAND", "BITOR", "LSHIFT",
+ "RSHIFT", "PLUS", "MINUS", "STAR",
+ "SLASH", "REM", "CONCAT", "COLLATE",
+ "BITNOT", "SEMI", "TRANSACTION", "ID_TRANS",
+ "COMMIT", "TO", "CREATE", "TABLE",
+ "LP", "RP", "AS", "DOT",
+ "ID_TAB_NEW", "ID_DB", "CTX_ROWID_KW", "EXISTS",
+ "COMMA", "ID_COL_NEW", "STRING", "JOIN_KW",
+ "ID_COL_TYPE", "CONSTRAINT", "DEFAULT", "NULL",
+ "PRIMARY", "UNIQUE", "CHECK", "REFERENCES",
+ "ID_CONSTR", "ID_COLLATE", "ID_TAB", "INTEGER",
+ "FLOAT", "BLOB", "AUTOINCR", "ON",
+ "INSERT", "DELETE", "UPDATE", "ID_FK_MATCH",
+ "SET", "DEFERRABLE", "FOREIGN", "DROP",
+ "ID_VIEW_NEW", "ID_VIEW", "UNION", "ALL",
+ "EXCEPT", "INTERSECT", "SELECT", "VALUES",
+ "DISTINCT", "ID_ALIAS", "FROM", "USING",
+ "JOIN", "ID_JOIN_OPTS", "ID_IDX", "ORDER",
+ "GROUP", "HAVING", "LIMIT", "WHERE",
+ "ID_COL", "INTO", "VARIABLE", "CASE",
+ "ID_FN", "ID_ERR_MSG", "WHEN", "THEN",
+ "ELSE", "INDEX", "ID_IDX_NEW", "ID_PRAGMA",
+ "ID_TRIG_NEW", "ID_TRIG", "ALTER", "ADD",
+ "error", "cmd", "input", "cmdlist",
+ "ecmd", "explain", "cmdx", "transtype",
+ "trans_opt", "nm", "savepoint_opt", "temp",
+ "ifnotexists", "fullname", "columnlist", "conslist_opt",
+ "table_options", "select", "column", "columnid",
+ "type", "carglist", "id", "ids",
+ "typetoken", "typename", "signed", "plus_num",
+ "minus_num", "ccons", "term", "expr",
+ "onconf", "sortorder", "autoinc", "idxlist_opt",
+ "refargs", "defer_subclause", "refarg", "refact",
+ "init_deferred_pred_opt", "conslist", "tconscomma", "tcons",
+ "idxlist", "defer_subclause_opt", "resolvetype", "orconf",
+ "raisetype", "ifexists", "select_stmt", "with",
+ "selectnowith", "oneselect", "multiselect_op", "values",
+ "distinct", "selcollist", "from", "where_opt",
+ "groupby_opt", "having_opt", "orderby_opt", "limit_opt",
+ "nexprlist", "exprlist", "sclp", "as",
+ "joinsrc", "singlesrc", "seltablist", "joinop",
+ "joinconstr_opt", "dbnm", "indexed_opt", "inscollist",
+ "sortlist", "delete_stmt", "update_stmt", "setlist",
+ "insert_stmt", "insert_cmd", "inscollist_opt", "exprx",
+ "not_opt", "likeop", "case_operand", "case_exprlist",
+ "case_else", "uniqueflag", "idxlist_single", "collate",
+ "nmnum", "number", "trigger_time", "trigger_event",
+ "foreach_clause", "when_clause", "trigger_cmd_list", "trigger_cmd",
+ "database_kw_opt", "key_opt", "kwcolumn_opt", "create_vtab",
+ "vtabarglist", "vtabarg", "vtabargtoken", "anylist",
+ "wqlist",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+ /* 0 */ "input ::= cmdlist",
+ /* 1 */ "cmdlist ::= cmdlist ecmd",
+ /* 2 */ "cmdlist ::= ecmd",
+ /* 3 */ "ecmd ::= SEMI",
+ /* 4 */ "ecmd ::= explain cmdx SEMI",
+ /* 5 */ "explain ::=",
+ /* 6 */ "explain ::= EXPLAIN",
+ /* 7 */ "explain ::= EXPLAIN QUERY PLAN",
+ /* 8 */ "cmdx ::= cmd",
+ /* 9 */ "cmd ::= BEGIN transtype trans_opt",
+ /* 10 */ "trans_opt ::=",
+ /* 11 */ "trans_opt ::= TRANSACTION",
+ /* 12 */ "trans_opt ::= TRANSACTION nm",
+ /* 13 */ "trans_opt ::= TRANSACTION ID_TRANS",
+ /* 14 */ "transtype ::=",
+ /* 15 */ "transtype ::= DEFERRED",
+ /* 16 */ "transtype ::= IMMEDIATE",
+ /* 17 */ "transtype ::= EXCLUSIVE",
+ /* 18 */ "cmd ::= COMMIT trans_opt",
+ /* 19 */ "cmd ::= END trans_opt",
+ /* 20 */ "cmd ::= ROLLBACK trans_opt",
+ /* 21 */ "savepoint_opt ::= SAVEPOINT",
+ /* 22 */ "savepoint_opt ::=",
+ /* 23 */ "cmd ::= SAVEPOINT nm",
+ /* 24 */ "cmd ::= RELEASE savepoint_opt nm",
+ /* 25 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
+ /* 26 */ "cmd ::= SAVEPOINT ID_TRANS",
+ /* 27 */ "cmd ::= RELEASE savepoint_opt ID_TRANS",
+ /* 28 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt ID_TRANS",
+ /* 29 */ "cmd ::= CREATE temp TABLE ifnotexists fullname LP columnlist conslist_opt RP table_options",
+ /* 30 */ "cmd ::= CREATE temp TABLE ifnotexists fullname AS select",
+ /* 31 */ "cmd ::= CREATE temp TABLE ifnotexists nm DOT ID_TAB_NEW",
+ /* 32 */ "cmd ::= CREATE temp TABLE ifnotexists ID_DB|ID_TAB_NEW",
+ /* 33 */ "table_options ::=",
+ /* 34 */ "table_options ::= WITHOUT nm",
+ /* 35 */ "table_options ::= WITHOUT CTX_ROWID_KW",
+ /* 36 */ "ifnotexists ::=",
+ /* 37 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 38 */ "temp ::= TEMP",
+ /* 39 */ "temp ::=",
+ /* 40 */ "columnlist ::= columnlist COMMA column",
+ /* 41 */ "columnlist ::= column",
+ /* 42 */ "column ::= columnid type carglist",
+ /* 43 */ "columnid ::= nm",
+ /* 44 */ "columnid ::= ID_COL_NEW",
+ /* 45 */ "id ::= ID",
+ /* 46 */ "ids ::= ID|STRING",
+ /* 47 */ "nm ::= id",
+ /* 48 */ "nm ::= STRING",
+ /* 49 */ "nm ::= JOIN_KW",
+ /* 50 */ "type ::=",
+ /* 51 */ "type ::= typetoken",
+ /* 52 */ "typetoken ::= typename",
+ /* 53 */ "typetoken ::= typename LP signed RP",
+ /* 54 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 55 */ "typename ::= ids",
+ /* 56 */ "typename ::= typename ids",
+ /* 57 */ "typename ::= ID_COL_TYPE",
+ /* 58 */ "signed ::= plus_num",
+ /* 59 */ "signed ::= minus_num",
+ /* 60 */ "carglist ::= carglist ccons",
+ /* 61 */ "carglist ::=",
+ /* 62 */ "ccons ::= CONSTRAINT nm",
+ /* 63 */ "ccons ::= DEFAULT term",
+ /* 64 */ "ccons ::= DEFAULT LP expr RP",
+ /* 65 */ "ccons ::= DEFAULT PLUS term",
+ /* 66 */ "ccons ::= DEFAULT MINUS term",
+ /* 67 */ "ccons ::= DEFAULT id",
+ /* 68 */ "ccons ::= DEFAULT CTIME_KW",
+ /* 69 */ "ccons ::= NULL onconf",
+ /* 70 */ "ccons ::= NOT NULL onconf",
+ /* 71 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 72 */ "ccons ::= UNIQUE onconf",
+ /* 73 */ "ccons ::= CHECK LP expr RP",
+ /* 74 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /* 75 */ "ccons ::= defer_subclause",
+ /* 76 */ "ccons ::= COLLATE ids",
+ /* 77 */ "ccons ::= CONSTRAINT ID_CONSTR",
+ /* 78 */ "ccons ::= COLLATE ID_COLLATE",
+ /* 79 */ "ccons ::= REFERENCES ID_TAB",
+ /* 80 */ "ccons ::= CHECK LP RP",
+ /* 81 */ "term ::= NULL",
+ /* 82 */ "term ::= INTEGER",
+ /* 83 */ "term ::= FLOAT",
+ /* 84 */ "term ::= STRING|BLOB",
+ /* 85 */ "autoinc ::=",
+ /* 86 */ "autoinc ::= AUTOINCR",
+ /* 87 */ "refargs ::=",
+ /* 88 */ "refargs ::= refargs refarg",
+ /* 89 */ "refarg ::= MATCH nm",
+ /* 90 */ "refarg ::= ON INSERT refact",
+ /* 91 */ "refarg ::= ON DELETE refact",
+ /* 92 */ "refarg ::= ON UPDATE refact",
+ /* 93 */ "refarg ::= MATCH ID_FK_MATCH",
+ /* 94 */ "refact ::= SET NULL",
+ /* 95 */ "refact ::= SET DEFAULT",
+ /* 96 */ "refact ::= CASCADE",
+ /* 97 */ "refact ::= RESTRICT",
+ /* 98 */ "refact ::= NO ACTION",
+ /* 99 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 100 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 101 */ "init_deferred_pred_opt ::=",
+ /* 102 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 103 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 104 */ "conslist_opt ::=",
+ /* 105 */ "conslist_opt ::= COMMA conslist",
+ /* 106 */ "conslist ::= conslist tconscomma tcons",
+ /* 107 */ "conslist ::= tcons",
+ /* 108 */ "tconscomma ::= COMMA",
+ /* 109 */ "tconscomma ::=",
+ /* 110 */ "tcons ::= CONSTRAINT nm",
+ /* 111 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
+ /* 112 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+ /* 113 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 114 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+ /* 115 */ "tcons ::= CONSTRAINT ID_CONSTR",
+ /* 116 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB",
+ /* 117 */ "tcons ::= CHECK LP RP onconf",
+ /* 118 */ "defer_subclause_opt ::=",
+ /* 119 */ "defer_subclause_opt ::= defer_subclause",
+ /* 120 */ "onconf ::=",
+ /* 121 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 122 */ "orconf ::=",
+ /* 123 */ "orconf ::= OR resolvetype",
+ /* 124 */ "resolvetype ::= raisetype",
+ /* 125 */ "resolvetype ::= IGNORE",
+ /* 126 */ "resolvetype ::= REPLACE",
+ /* 127 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 128 */ "cmd ::= DROP TABLE ifexists nm DOT ID_TAB",
+ /* 129 */ "cmd ::= DROP TABLE ifexists ID_DB|ID_TAB",
+ /* 130 */ "ifexists ::= IF EXISTS",
+ /* 131 */ "ifexists ::=",
+ /* 132 */ "cmd ::= CREATE temp VIEW ifnotexists fullname AS select",
+ /* 133 */ "cmd ::= CREATE temp VIEW ifnotexists nm DOT ID_VIEW_NEW",
+ /* 134 */ "cmd ::= CREATE temp VIEW ifnotexists ID_DB|ID_VIEW_NEW",
+ /* 135 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 136 */ "cmd ::= DROP VIEW ifexists nm DOT ID_VIEW",
+ /* 137 */ "cmd ::= DROP VIEW ifexists ID_DB|ID_VIEW",
+ /* 138 */ "cmd ::= select_stmt",
+ /* 139 */ "select_stmt ::= select",
+ /* 140 */ "select ::= with selectnowith",
+ /* 141 */ "selectnowith ::= oneselect",
+ /* 142 */ "selectnowith ::= selectnowith multiselect_op oneselect",
+ /* 143 */ "selectnowith ::= values",
+ /* 144 */ "selectnowith ::= selectnowith COMMA values",
+ /* 145 */ "multiselect_op ::= UNION",
+ /* 146 */ "multiselect_op ::= UNION ALL",
+ /* 147 */ "multiselect_op ::= EXCEPT",
+ /* 148 */ "multiselect_op ::= INTERSECT",
+ /* 149 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 150 */ "values ::= VALUES LP nexprlist RP",
+ /* 151 */ "values ::= values COMMA LP exprlist RP",
+ /* 152 */ "distinct ::= DISTINCT",
+ /* 153 */ "distinct ::= ALL",
+ /* 154 */ "distinct ::=",
+ /* 155 */ "sclp ::= selcollist COMMA",
+ /* 156 */ "sclp ::=",
+ /* 157 */ "selcollist ::= sclp expr as",
+ /* 158 */ "selcollist ::= sclp STAR",
+ /* 159 */ "selcollist ::= sclp nm DOT STAR",
+ /* 160 */ "selcollist ::= sclp",
+ /* 161 */ "selcollist ::= sclp ID_TAB DOT STAR",
+ /* 162 */ "as ::= AS nm",
+ /* 163 */ "as ::= ids",
+ /* 164 */ "as ::= AS ID_ALIAS",
+ /* 165 */ "as ::= ID_ALIAS",
+ /* 166 */ "as ::=",
+ /* 167 */ "from ::=",
+ /* 168 */ "from ::= FROM joinsrc",
+ /* 169 */ "joinsrc ::= singlesrc seltablist",
+ /* 170 */ "joinsrc ::=",
+ /* 171 */ "seltablist ::= seltablist joinop singlesrc joinconstr_opt",
+ /* 172 */ "seltablist ::=",
+ /* 173 */ "singlesrc ::= nm dbnm as indexed_opt",
+ /* 174 */ "singlesrc ::= LP select RP as",
+ /* 175 */ "singlesrc ::= LP joinsrc RP as",
+ /* 176 */ "singlesrc ::=",
+ /* 177 */ "singlesrc ::= nm DOT",
+ /* 178 */ "singlesrc ::= nm DOT ID_TAB",
+ /* 179 */ "singlesrc ::= ID_DB|ID_TAB",
+ /* 180 */ "singlesrc ::= nm DOT ID_VIEW",
+ /* 181 */ "singlesrc ::= ID_DB|ID_VIEW",
+ /* 182 */ "joinconstr_opt ::= ON expr",
+ /* 183 */ "joinconstr_opt ::= USING LP inscollist RP",
+ /* 184 */ "joinconstr_opt ::=",
+ /* 185 */ "dbnm ::=",
+ /* 186 */ "dbnm ::= DOT nm",
+ /* 187 */ "fullname ::= nm dbnm",
+ /* 188 */ "joinop ::= COMMA",
+ /* 189 */ "joinop ::= JOIN",
+ /* 190 */ "joinop ::= JOIN_KW JOIN",
+ /* 191 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 192 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 193 */ "joinop ::= ID_JOIN_OPTS",
+ /* 194 */ "indexed_opt ::=",
+ /* 195 */ "indexed_opt ::= INDEXED BY nm",
+ /* 196 */ "indexed_opt ::= NOT INDEXED",
+ /* 197 */ "indexed_opt ::= INDEXED BY ID_IDX",
+ /* 198 */ "orderby_opt ::=",
+ /* 199 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 200 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 201 */ "sortlist ::= expr sortorder",
+ /* 202 */ "sortorder ::= ASC",
+ /* 203 */ "sortorder ::= DESC",
+ /* 204 */ "sortorder ::=",
+ /* 205 */ "groupby_opt ::=",
+ /* 206 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 207 */ "groupby_opt ::= GROUP BY",
+ /* 208 */ "having_opt ::=",
+ /* 209 */ "having_opt ::= HAVING expr",
+ /* 210 */ "limit_opt ::=",
+ /* 211 */ "limit_opt ::= LIMIT expr",
+ /* 212 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 213 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 214 */ "cmd ::= delete_stmt",
+ /* 215 */ "delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt",
+ /* 216 */ "delete_stmt ::= with DELETE FROM",
+ /* 217 */ "delete_stmt ::= with DELETE FROM nm DOT",
+ /* 218 */ "delete_stmt ::= with DELETE FROM nm DOT ID_TAB",
+ /* 219 */ "delete_stmt ::= with DELETE FROM ID_DB|ID_TAB",
+ /* 220 */ "where_opt ::=",
+ /* 221 */ "where_opt ::= WHERE expr",
+ /* 222 */ "where_opt ::= WHERE",
+ /* 223 */ "cmd ::= update_stmt",
+ /* 224 */ "update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
+ /* 225 */ "update_stmt ::= with UPDATE orconf",
+ /* 226 */ "update_stmt ::= with UPDATE orconf nm DOT",
+ /* 227 */ "update_stmt ::= with UPDATE orconf nm DOT ID_TAB",
+ /* 228 */ "update_stmt ::= with UPDATE orconf ID_DB|ID_TAB",
+ /* 229 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 230 */ "setlist ::= nm EQ expr",
+ /* 231 */ "setlist ::=",
+ /* 232 */ "setlist ::= setlist COMMA",
+ /* 233 */ "setlist ::= setlist COMMA ID_COL",
+ /* 234 */ "setlist ::= ID_COL",
+ /* 235 */ "cmd ::= insert_stmt",
+ /* 236 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select",
+ /* 237 */ "insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
+ /* 238 */ "insert_stmt ::= with insert_cmd INTO",
+ /* 239 */ "insert_stmt ::= with insert_cmd INTO nm DOT",
+ /* 240 */ "insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB",
+ /* 241 */ "insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB",
+ /* 242 */ "insert_cmd ::= INSERT orconf",
+ /* 243 */ "insert_cmd ::= REPLACE",
+ /* 244 */ "inscollist_opt ::=",
+ /* 245 */ "inscollist_opt ::= LP inscollist RP",
+ /* 246 */ "inscollist ::= inscollist COMMA nm",
+ /* 247 */ "inscollist ::= nm",
+ /* 248 */ "inscollist ::=",
+ /* 249 */ "inscollist ::= inscollist COMMA ID_COL",
+ /* 250 */ "inscollist ::= ID_COL",
+ /* 251 */ "exprx ::= term",
+ /* 252 */ "exprx ::= CTIME_KW",
+ /* 253 */ "exprx ::= LP expr RP",
+ /* 254 */ "exprx ::= id",
+ /* 255 */ "exprx ::= JOIN_KW",
+ /* 256 */ "exprx ::= nm DOT nm",
+ /* 257 */ "exprx ::= nm DOT nm DOT nm",
+ /* 258 */ "exprx ::= VARIABLE",
+ /* 259 */ "exprx ::= expr COLLATE ids",
+ /* 260 */ "exprx ::= CAST LP expr AS typetoken RP",
+ /* 261 */ "exprx ::= ID LP distinct exprlist RP",
+ /* 262 */ "exprx ::= ID LP STAR RP",
+ /* 263 */ "exprx ::= expr AND expr",
+ /* 264 */ "exprx ::= expr OR expr",
+ /* 265 */ "exprx ::= expr LT|GT|GE|LE expr",
+ /* 266 */ "exprx ::= expr EQ|NE expr",
+ /* 267 */ "exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 268 */ "exprx ::= expr PLUS|MINUS expr",
+ /* 269 */ "exprx ::= expr STAR|SLASH|REM expr",
+ /* 270 */ "exprx ::= expr CONCAT expr",
+ /* 271 */ "exprx ::= expr not_opt likeop expr",
+ /* 272 */ "exprx ::= expr not_opt likeop expr ESCAPE expr",
+ /* 273 */ "exprx ::= expr ISNULL|NOTNULL",
+ /* 274 */ "exprx ::= expr NOT NULL",
+ /* 275 */ "exprx ::= expr IS not_opt expr",
+ /* 276 */ "exprx ::= NOT expr",
+ /* 277 */ "exprx ::= BITNOT expr",
+ /* 278 */ "exprx ::= MINUS expr",
+ /* 279 */ "exprx ::= PLUS expr",
+ /* 280 */ "exprx ::= expr not_opt BETWEEN expr AND expr",
+ /* 281 */ "exprx ::= expr not_opt IN LP exprlist RP",
+ /* 282 */ "exprx ::= LP select RP",
+ /* 283 */ "exprx ::= expr not_opt IN LP select RP",
+ /* 284 */ "exprx ::= expr not_opt IN nm dbnm",
+ /* 285 */ "exprx ::= EXISTS LP select RP",
+ /* 286 */ "exprx ::= CASE case_operand case_exprlist case_else END",
+ /* 287 */ "exprx ::= RAISE LP IGNORE RP",
+ /* 288 */ "exprx ::= RAISE LP raisetype COMMA nm RP",
+ /* 289 */ "exprx ::= nm DOT",
+ /* 290 */ "exprx ::= nm DOT nm DOT",
+ /* 291 */ "exprx ::= expr not_opt BETWEEN expr",
+ /* 292 */ "exprx ::= CASE case_operand case_exprlist case_else",
+ /* 293 */ "exprx ::= expr not_opt IN LP exprlist",
+ /* 294 */ "exprx ::= expr not_opt IN ID_DB",
+ /* 295 */ "exprx ::= expr not_opt IN nm DOT ID_TAB",
+ /* 296 */ "exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN",
+ /* 297 */ "exprx ::= nm DOT ID_TAB|ID_COL",
+ /* 298 */ "exprx ::= nm DOT nm DOT ID_COL",
+ /* 299 */ "exprx ::= expr COLLATE ID_COLLATE",
+ /* 300 */ "exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP",
+ /* 301 */ "expr ::= exprx",
+ /* 302 */ "expr ::=",
+ /* 303 */ "not_opt ::=",
+ /* 304 */ "not_opt ::= NOT",
+ /* 305 */ "likeop ::= LIKE_KW|MATCH",
+ /* 306 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 307 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 308 */ "case_else ::= ELSE expr",
+ /* 309 */ "case_else ::=",
+ /* 310 */ "case_operand ::= exprx",
+ /* 311 */ "case_operand ::=",
+ /* 312 */ "exprlist ::= nexprlist",
+ /* 313 */ "exprlist ::=",
+ /* 314 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 315 */ "nexprlist ::= exprx",
+ /* 316 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt",
+ /* 317 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB",
+ /* 318 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW",
+ /* 319 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW",
+ /* 320 */ "uniqueflag ::= UNIQUE",
+ /* 321 */ "uniqueflag ::=",
+ /* 322 */ "idxlist_opt ::=",
+ /* 323 */ "idxlist_opt ::= LP idxlist RP",
+ /* 324 */ "idxlist ::= idxlist COMMA idxlist_single",
+ /* 325 */ "idxlist ::= idxlist_single",
+ /* 326 */ "idxlist_single ::= nm collate sortorder",
+ /* 327 */ "idxlist_single ::= ID_COL",
+ /* 328 */ "collate ::=",
+ /* 329 */ "collate ::= COLLATE ids",
+ /* 330 */ "collate ::= COLLATE ID_COLLATE",
+ /* 331 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 332 */ "cmd ::= DROP INDEX ifexists nm DOT ID_IDX",
+ /* 333 */ "cmd ::= DROP INDEX ifexists ID_DB|ID_IDX",
+ /* 334 */ "cmd ::= VACUUM",
+ /* 335 */ "cmd ::= VACUUM nm",
+ /* 336 */ "cmd ::= PRAGMA nm dbnm",
+ /* 337 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 338 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 339 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 340 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 341 */ "cmd ::= PRAGMA nm DOT ID_PRAGMA",
+ /* 342 */ "cmd ::= PRAGMA ID_DB|ID_PRAGMA",
+ /* 343 */ "nmnum ::= plus_num",
+ /* 344 */ "nmnum ::= nm",
+ /* 345 */ "nmnum ::= ON",
+ /* 346 */ "nmnum ::= DELETE",
+ /* 347 */ "nmnum ::= DEFAULT",
+ /* 348 */ "plus_num ::= PLUS number",
+ /* 349 */ "plus_num ::= number",
+ /* 350 */ "minus_num ::= MINUS number",
+ /* 351 */ "number ::= INTEGER",
+ /* 352 */ "number ::= FLOAT",
+ /* 353 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END",
+ /* 354 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause",
+ /* 355 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list",
+ /* 356 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB",
+ /* 357 */ "cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW",
+ /* 358 */ "cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW",
+ /* 359 */ "trigger_time ::= BEFORE",
+ /* 360 */ "trigger_time ::= AFTER",
+ /* 361 */ "trigger_time ::= INSTEAD OF",
+ /* 362 */ "trigger_time ::=",
+ /* 363 */ "trigger_event ::= DELETE",
+ /* 364 */ "trigger_event ::= INSERT",
+ /* 365 */ "trigger_event ::= UPDATE",
+ /* 366 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 367 */ "foreach_clause ::=",
+ /* 368 */ "foreach_clause ::= FOR EACH ROW",
+ /* 369 */ "when_clause ::=",
+ /* 370 */ "when_clause ::= WHEN expr",
+ /* 371 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 372 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 373 */ "trigger_cmd_list ::= SEMI",
+ /* 374 */ "trigger_cmd ::= update_stmt",
+ /* 375 */ "trigger_cmd ::= insert_stmt",
+ /* 376 */ "trigger_cmd ::= delete_stmt",
+ /* 377 */ "trigger_cmd ::= select_stmt",
+ /* 378 */ "raisetype ::= ROLLBACK|ABORT|FAIL",
+ /* 379 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 380 */ "cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG",
+ /* 381 */ "cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG",
+ /* 382 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 383 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 384 */ "key_opt ::=",
+ /* 385 */ "key_opt ::= KEY expr",
+ /* 386 */ "database_kw_opt ::= DATABASE",
+ /* 387 */ "database_kw_opt ::=",
+ /* 388 */ "cmd ::= REINDEX",
+ /* 389 */ "cmd ::= REINDEX nm dbnm",
+ /* 390 */ "cmd ::= REINDEX ID_COLLATE",
+ /* 391 */ "cmd ::= REINDEX nm DOT ID_TAB|ID_IDX",
+ /* 392 */ "cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB",
+ /* 393 */ "cmd ::= ANALYZE",
+ /* 394 */ "cmd ::= ANALYZE nm dbnm",
+ /* 395 */ "cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX",
+ /* 396 */ "cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB",
+ /* 397 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 398 */ "cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column",
+ /* 399 */ "cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW",
+ /* 400 */ "cmd ::= ALTER TABLE nm DOT ID_TAB",
+ /* 401 */ "cmd ::= ALTER TABLE ID_DB|ID_TAB",
+ /* 402 */ "kwcolumn_opt ::=",
+ /* 403 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 404 */ "cmd ::= create_vtab",
+ /* 405 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 406 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP",
+ /* 407 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW",
+ /* 408 */ "create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW",
+ /* 409 */ "vtabarglist ::= vtabarg",
+ /* 410 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 411 */ "vtabarg ::=",
+ /* 412 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 413 */ "vtabargtoken ::= ANY",
+ /* 414 */ "vtabargtoken ::= LP anylist RP",
+ /* 415 */ "anylist ::=",
+ /* 416 */ "anylist ::= anylist LP anylist RP",
+ /* 417 */ "anylist ::= anylist ANY",
+ /* 418 */ "with ::=",
+ /* 419 */ "with ::= WITH wqlist",
+ /* 420 */ "with ::= WITH RECURSIVE wqlist",
+ /* 421 */ "wqlist ::= nm idxlist_opt AS LP select RP",
+ /* 422 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP",
+ /* 423 */ "wqlist ::= ID_TAB_NEW",
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.
+*/
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
+#endif
+ }
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to sqlite3_parse and sqlite3_parseFree.
+*/
+void *sqlite3_parseAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+#ifdef YYTRACKMAXSTACKDEPTH
+ pParser->yyidxMax = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ pParser->yystack = NULL;
+ pParser->yystksz = 0;
+ yyGrowStack(pParser);
+#endif
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(
+ yyParser *yypParser, /* The parser */
+ YYCODETYPE yymajor, /* Type code for object to destroy */
+ YYMINORTYPE *yypminor /* The object to be destroyed */
+){
+ sqlite3_parseARG_FETCH;
+ if (parserContext->executeRules)
+ {
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+ case 169: /* cmd */
+ case 172: /* ecmd */
+ case 174: /* cmdx */
+ case 218: /* select_stmt */
+ case 245: /* delete_stmt */
+ case 246: /* update_stmt */
+ case 248: /* insert_stmt */
+ case 267: /* trigger_cmd */
+ case 271: /* create_vtab */
+{
+delete (yypminor->yy399);
+}
+ break;
+ case 173: /* explain */
+{
+delete (yypminor->yy225);
+}
+ break;
+ case 175: /* transtype */
+ case 176: /* trans_opt */
+{
+delete (yypminor->yy300);
+}
+ break;
+ case 177: /* nm */
+ case 184: /* table_options */
+ case 187: /* columnid */
+ case 190: /* id */
+ case 191: /* ids */
+ case 193: /* typename */
+ case 241: /* dbnm */
+ case 259: /* collate */
+ case 273: /* vtabarg */
+ case 274: /* vtabargtoken */
+ case 275: /* anylist */
+{
+delete (yypminor->yy211);
+}
+ break;
+ case 178: /* savepoint_opt */
+ case 180: /* ifnotexists */
+ case 202: /* autoinc */
+ case 210: /* tconscomma */
+ case 217: /* ifexists */
+ case 252: /* not_opt */
+ case 257: /* uniqueflag */
+ case 268: /* database_kw_opt */
+ case 270: /* kwcolumn_opt */
+{
+delete (yypminor->yy237);
+}
+ break;
+ case 179: /* temp */
+ case 224: /* distinct */
+{
+delete (yypminor->yy376);
+}
+ break;
+ case 181: /* fullname */
+{
+delete (yypminor->yy66);
+}
+ break;
+ case 182: /* columnlist */
+{
+delete (yypminor->yy118);
+}
+ break;
+ case 183: /* conslist_opt */
+ case 209: /* conslist */
+{
+delete (yypminor->yy87);
+}
+ break;
+ case 185: /* select */
+ case 220: /* selectnowith */
+{
+delete (yypminor->yy123);
+}
+ break;
+ case 186: /* column */
+{
+delete (yypminor->yy425);
+}
+ break;
+ case 188: /* type */
+ case 192: /* typetoken */
+{
+delete (yypminor->yy299);
+}
+ break;
+ case 189: /* carglist */
+{
+delete (yypminor->yy449);
+}
+ break;
+ case 194: /* signed */
+ case 195: /* plus_num */
+ case 196: /* minus_num */
+ case 198: /* term */
+ case 260: /* nmnum */
+ case 261: /* number */
+{
+delete (yypminor->yy21);
+}
+ break;
+ case 197: /* ccons */
+{
+delete (yypminor->yy4);
+}
+ break;
+ case 199: /* expr */
+ case 227: /* where_opt */
+ case 229: /* having_opt */
+ case 251: /* exprx */
+ case 254: /* case_operand */
+ case 256: /* case_else */
+{
+delete (yypminor->yy490);
+}
+ break;
+ case 200: /* onconf */
+ case 214: /* resolvetype */
+ case 215: /* orconf */
+{
+delete (yypminor->yy30);
+}
+ break;
+ case 201: /* sortorder */
+{
+delete (yypminor->yy226);
+}
+ break;
+ case 203: /* idxlist_opt */
+ case 212: /* idxlist */
+{
+delete (yypminor->yy139);
+}
+ break;
+ case 204: /* refargs */
+{
+delete (yypminor->yy108);
+}
+ break;
+ case 205: /* defer_subclause */
+ case 213: /* defer_subclause_opt */
+{
+delete (yypminor->yy131);
+}
+ break;
+ case 206: /* refarg */
+{
+delete (yypminor->yy271);
+}
+ break;
+ case 207: /* refact */
+{
+delete (yypminor->yy312);
+}
+ break;
+ case 208: /* init_deferred_pred_opt */
+{
+delete (yypminor->yy498);
+}
+ break;
+ case 211: /* tcons */
+{
+delete (yypminor->yy8);
+}
+ break;
+ case 219: /* with */
+ case 276: /* wqlist */
+{
+delete (yypminor->yy367);
+}
+ break;
+ case 221: /* oneselect */
+{
+delete (yypminor->yy468);
+}
+ break;
+ case 222: /* multiselect_op */
+{
+delete (yypminor->yy168);
+}
+ break;
+ case 223: /* values */
+{
+delete (yypminor->yy416);
+}
+ break;
+ case 225: /* selcollist */
+ case 234: /* sclp */
+{
+delete (yypminor->yy263);
+}
+ break;
+ case 226: /* from */
+ case 236: /* joinsrc */
+{
+delete (yypminor->yy373);
+}
+ break;
+ case 228: /* groupby_opt */
+ case 232: /* nexprlist */
+ case 233: /* exprlist */
+ case 255: /* case_exprlist */
+{
+delete (yypminor->yy13);
+}
+ break;
+ case 230: /* orderby_opt */
+ case 244: /* sortlist */
+{
+delete (yypminor->yy495);
+}
+ break;
+ case 231: /* limit_opt */
+{
+delete (yypminor->yy128);
+}
+ break;
+ case 235: /* as */
+{
+delete (yypminor->yy28);
+}
+ break;
+ case 237: /* singlesrc */
+{
+delete (yypminor->yy173);
+}
+ break;
+ case 238: /* seltablist */
+{
+delete (yypminor->yy359);
+}
+ break;
+ case 239: /* joinop */
+{
+delete (yypminor->yy473);
+}
+ break;
+ case 240: /* joinconstr_opt */
+{
+delete (yypminor->yy117);
+}
+ break;
+ case 242: /* indexed_opt */
+{
+delete (yypminor->yy472);
+}
+ break;
+ case 243: /* inscollist */
+ case 250: /* inscollist_opt */
+ case 272: /* vtabarglist */
+{
+delete (yypminor->yy445);
+}
+ break;
+ case 247: /* setlist */
+{
+delete (yypminor->yy381);
+}
+ break;
+ case 249: /* insert_cmd */
+{
+delete (yypminor->yy250);
+}
+ break;
+ case 253: /* likeop */
+{
+delete (yypminor->yy374);
+}
+ break;
+ case 258: /* idxlist_single */
+{
+delete (yypminor->yy90);
+}
+ break;
+ case 262: /* trigger_time */
+{
+delete (yypminor->yy152);
+}
+ break;
+ case 263: /* trigger_event */
+{
+delete (yypminor->yy309);
+}
+ break;
+ case 264: /* foreach_clause */
+{
+delete (yypminor->yy409);
+}
+ break;
+ case 265: /* when_clause */
+ case 269: /* key_opt */
+{
+if ((yypminor->yy490)) delete (yypminor->yy490);
+}
+ break;
+ case 266: /* trigger_cmd_list */
+{
+delete (yypminor->yy214);
+}
+ break;
+ default: break; /* If no destructor action specified: do nothing */
+ }
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+ /* There is no mechanism by which the parser stack can be popped below
+ ** empty in SQLite. */
+ if( pParser->yyidx<0 ) return 0;
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor(pParser, yymajor, &yytos->minor);
+ delete yytos->tokens;
+ yytos->tokens = nullptr;
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from sqlite3_parseAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void sqlite3_parseFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ /* In SQLite, we never try to destroy a parser that was not successfully
+ ** created in the first place. */
+ if( pParser==0 ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int sqlite3_parseStackPeak(void *p){
+ yyParser *pParser = (yyParser*)p;
+ return pParser->yyidxMax;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+ GET_CONTEXT;
+
+ if( stateno>YY_SHIFT_COUNT
+ || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
+#ifdef YYFALLBACK
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0
+ && parserContext->doFallbacks ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
+#if YY_SHIFT_MIN+YYWILDCARD<0
+ j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+ j<YY_ACTTAB_COUNT &&
+#endif
+ yy_lookahead[j]==YYWILDCARD
+ ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
+ }
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ int stateno, /* Current state number */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+#ifdef YYERRORSYMBOL
+ if( stateno>YY_REDUCE_COUNT ){
+ return yy_default[stateno];
+ }
+#else
+ assert( stateno<=YY_REDUCE_COUNT );
+#endif
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+#ifdef YYERRORSYMBOL
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }
+#else
+ assert( i>=0 && i<YY_ACTTAB_COUNT );
+ assert( yy_lookahead[i]==iLookAhead );
+#endif
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ sqlite3_parseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+
+ UNUSED_PARAMETER(yypMinor);
+ parserContext->error(QObject::tr("Parser stack overflow"));
+ sqlite3_parseARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( yypParser->yyidx>yypParser->yyidxMax ){
+ yypParser->yyidxMax = yypParser->yyidx;
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = (YYACTIONTYPE)yyNewState;
+ yytos->major = (YYCODETYPE)yyMajor;
+ yytos->minor = *yypMinor;
+ yytos->tokens = new QList<Token*>();
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 170, 1 },
+ { 171, 2 },
+ { 171, 1 },
+ { 172, 1 },
+ { 172, 3 },
+ { 173, 0 },
+ { 173, 1 },
+ { 173, 3 },
+ { 174, 1 },
+ { 169, 3 },
+ { 176, 0 },
+ { 176, 1 },
+ { 176, 2 },
+ { 176, 2 },
+ { 175, 0 },
+ { 175, 1 },
+ { 175, 1 },
+ { 175, 1 },
+ { 169, 2 },
+ { 169, 2 },
+ { 169, 2 },
+ { 178, 1 },
+ { 178, 0 },
+ { 169, 2 },
+ { 169, 3 },
+ { 169, 5 },
+ { 169, 2 },
+ { 169, 3 },
+ { 169, 5 },
+ { 169, 10 },
+ { 169, 7 },
+ { 169, 7 },
+ { 169, 5 },
+ { 184, 0 },
+ { 184, 2 },
+ { 184, 2 },
+ { 180, 0 },
+ { 180, 3 },
+ { 179, 1 },
+ { 179, 0 },
+ { 182, 3 },
+ { 182, 1 },
+ { 186, 3 },
+ { 187, 1 },
+ { 187, 1 },
+ { 190, 1 },
+ { 191, 1 },
+ { 177, 1 },
+ { 177, 1 },
+ { 177, 1 },
+ { 188, 0 },
+ { 188, 1 },
+ { 192, 1 },
+ { 192, 4 },
+ { 192, 6 },
+ { 193, 1 },
+ { 193, 2 },
+ { 193, 1 },
+ { 194, 1 },
+ { 194, 1 },
+ { 189, 2 },
+ { 189, 0 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 4 },
+ { 197, 3 },
+ { 197, 3 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 3 },
+ { 197, 5 },
+ { 197, 2 },
+ { 197, 4 },
+ { 197, 4 },
+ { 197, 1 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 2 },
+ { 197, 3 },
+ { 198, 1 },
+ { 198, 1 },
+ { 198, 1 },
+ { 198, 1 },
+ { 202, 0 },
+ { 202, 1 },
+ { 204, 0 },
+ { 204, 2 },
+ { 206, 2 },
+ { 206, 3 },
+ { 206, 3 },
+ { 206, 3 },
+ { 206, 2 },
+ { 207, 2 },
+ { 207, 2 },
+ { 207, 1 },
+ { 207, 1 },
+ { 207, 2 },
+ { 205, 3 },
+ { 205, 2 },
+ { 208, 0 },
+ { 208, 2 },
+ { 208, 2 },
+ { 183, 0 },
+ { 183, 2 },
+ { 209, 3 },
+ { 209, 1 },
+ { 210, 1 },
+ { 210, 0 },
+ { 211, 2 },
+ { 211, 7 },
+ { 211, 5 },
+ { 211, 5 },
+ { 211, 10 },
+ { 211, 2 },
+ { 211, 7 },
+ { 211, 4 },
+ { 213, 0 },
+ { 213, 1 },
+ { 200, 0 },
+ { 200, 3 },
+ { 215, 0 },
+ { 215, 2 },
+ { 214, 1 },
+ { 214, 1 },
+ { 214, 1 },
+ { 169, 4 },
+ { 169, 6 },
+ { 169, 4 },
+ { 217, 2 },
+ { 217, 0 },
+ { 169, 7 },
+ { 169, 7 },
+ { 169, 5 },
+ { 169, 4 },
+ { 169, 6 },
+ { 169, 4 },
+ { 169, 1 },
+ { 218, 1 },
+ { 185, 2 },
+ { 220, 1 },
+ { 220, 3 },
+ { 220, 1 },
+ { 220, 3 },
+ { 222, 1 },
+ { 222, 2 },
+ { 222, 1 },
+ { 222, 1 },
+ { 221, 9 },
+ { 223, 4 },
+ { 223, 5 },
+ { 224, 1 },
+ { 224, 1 },
+ { 224, 0 },
+ { 234, 2 },
+ { 234, 0 },
+ { 225, 3 },
+ { 225, 2 },
+ { 225, 4 },
+ { 225, 1 },
+ { 225, 4 },
+ { 235, 2 },
+ { 235, 1 },
+ { 235, 2 },
+ { 235, 1 },
+ { 235, 0 },
+ { 226, 0 },
+ { 226, 2 },
+ { 236, 2 },
+ { 236, 0 },
+ { 238, 4 },
+ { 238, 0 },
+ { 237, 4 },
+ { 237, 4 },
+ { 237, 4 },
+ { 237, 0 },
+ { 237, 2 },
+ { 237, 3 },
+ { 237, 1 },
+ { 237, 3 },
+ { 237, 1 },
+ { 240, 2 },
+ { 240, 4 },
+ { 240, 0 },
+ { 241, 0 },
+ { 241, 2 },
+ { 181, 2 },
+ { 239, 1 },
+ { 239, 1 },
+ { 239, 2 },
+ { 239, 3 },
+ { 239, 4 },
+ { 239, 1 },
+ { 242, 0 },
+ { 242, 3 },
+ { 242, 2 },
+ { 242, 3 },
+ { 230, 0 },
+ { 230, 3 },
+ { 244, 4 },
+ { 244, 2 },
+ { 201, 1 },
+ { 201, 1 },
+ { 201, 0 },
+ { 228, 0 },
+ { 228, 3 },
+ { 228, 2 },
+ { 229, 0 },
+ { 229, 2 },
+ { 231, 0 },
+ { 231, 2 },
+ { 231, 4 },
+ { 231, 4 },
+ { 169, 1 },
+ { 245, 6 },
+ { 245, 3 },
+ { 245, 5 },
+ { 245, 6 },
+ { 245, 4 },
+ { 227, 0 },
+ { 227, 2 },
+ { 227, 1 },
+ { 169, 1 },
+ { 246, 8 },
+ { 246, 3 },
+ { 246, 5 },
+ { 246, 6 },
+ { 246, 4 },
+ { 247, 5 },
+ { 247, 3 },
+ { 247, 0 },
+ { 247, 2 },
+ { 247, 3 },
+ { 247, 1 },
+ { 169, 1 },
+ { 248, 6 },
+ { 248, 7 },
+ { 248, 3 },
+ { 248, 5 },
+ { 248, 4 },
+ { 248, 6 },
+ { 249, 2 },
+ { 249, 1 },
+ { 250, 0 },
+ { 250, 3 },
+ { 243, 3 },
+ { 243, 1 },
+ { 243, 0 },
+ { 243, 3 },
+ { 243, 1 },
+ { 251, 1 },
+ { 251, 1 },
+ { 251, 3 },
+ { 251, 1 },
+ { 251, 1 },
+ { 251, 3 },
+ { 251, 5 },
+ { 251, 1 },
+ { 251, 3 },
+ { 251, 6 },
+ { 251, 5 },
+ { 251, 4 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 3 },
+ { 251, 4 },
+ { 251, 6 },
+ { 251, 2 },
+ { 251, 3 },
+ { 251, 4 },
+ { 251, 2 },
+ { 251, 2 },
+ { 251, 2 },
+ { 251, 2 },
+ { 251, 6 },
+ { 251, 6 },
+ { 251, 3 },
+ { 251, 6 },
+ { 251, 5 },
+ { 251, 4 },
+ { 251, 5 },
+ { 251, 4 },
+ { 251, 6 },
+ { 251, 2 },
+ { 251, 4 },
+ { 251, 4 },
+ { 251, 4 },
+ { 251, 5 },
+ { 251, 4 },
+ { 251, 6 },
+ { 251, 1 },
+ { 251, 3 },
+ { 251, 5 },
+ { 251, 3 },
+ { 251, 6 },
+ { 199, 1 },
+ { 199, 0 },
+ { 252, 0 },
+ { 252, 1 },
+ { 253, 1 },
+ { 255, 5 },
+ { 255, 4 },
+ { 256, 2 },
+ { 256, 0 },
+ { 254, 1 },
+ { 254, 0 },
+ { 233, 1 },
+ { 233, 0 },
+ { 232, 3 },
+ { 232, 1 },
+ { 169, 12 },
+ { 169, 8 },
+ { 169, 7 },
+ { 169, 5 },
+ { 257, 1 },
+ { 257, 0 },
+ { 203, 0 },
+ { 203, 3 },
+ { 212, 3 },
+ { 212, 1 },
+ { 258, 3 },
+ { 258, 1 },
+ { 259, 0 },
+ { 259, 2 },
+ { 259, 2 },
+ { 169, 4 },
+ { 169, 6 },
+ { 169, 4 },
+ { 169, 1 },
+ { 169, 2 },
+ { 169, 3 },
+ { 169, 5 },
+ { 169, 6 },
+ { 169, 5 },
+ { 169, 6 },
+ { 169, 4 },
+ { 169, 2 },
+ { 260, 1 },
+ { 260, 1 },
+ { 260, 1 },
+ { 260, 1 },
+ { 260, 1 },
+ { 195, 2 },
+ { 195, 1 },
+ { 196, 2 },
+ { 261, 1 },
+ { 261, 1 },
+ { 169, 15 },
+ { 169, 12 },
+ { 169, 14 },
+ { 169, 10 },
+ { 169, 7 },
+ { 169, 5 },
+ { 262, 1 },
+ { 262, 1 },
+ { 262, 2 },
+ { 262, 0 },
+ { 263, 1 },
+ { 263, 1 },
+ { 263, 1 },
+ { 263, 3 },
+ { 264, 0 },
+ { 264, 3 },
+ { 265, 0 },
+ { 265, 2 },
+ { 266, 3 },
+ { 266, 2 },
+ { 266, 1 },
+ { 267, 1 },
+ { 267, 1 },
+ { 267, 1 },
+ { 267, 1 },
+ { 216, 1 },
+ { 169, 4 },
+ { 169, 6 },
+ { 169, 4 },
+ { 169, 6 },
+ { 169, 3 },
+ { 269, 0 },
+ { 269, 2 },
+ { 268, 1 },
+ { 268, 0 },
+ { 169, 1 },
+ { 169, 3 },
+ { 169, 2 },
+ { 169, 4 },
+ { 169, 2 },
+ { 169, 1 },
+ { 169, 3 },
+ { 169, 4 },
+ { 169, 2 },
+ { 169, 6 },
+ { 169, 6 },
+ { 169, 6 },
+ { 169, 5 },
+ { 169, 3 },
+ { 270, 0 },
+ { 270, 1 },
+ { 169, 1 },
+ { 271, 8 },
+ { 271, 11 },
+ { 271, 7 },
+ { 271, 5 },
+ { 272, 1 },
+ { 272, 3 },
+ { 273, 0 },
+ { 273, 2 },
+ { 274, 1 },
+ { 274, 3 },
+ { 275, 0 },
+ { 275, 4 },
+ { 275, 2 },
+ { 219, 0 },
+ { 219, 2 },
+ { 219, 3 },
+ { 276, 6 },
+ { 276, 8 },
+ { 276, 1 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ sqlite3_parseARG_FETCH;
+ SqliteStatement* objectForTokens = 0;
+ QStringList noTokenInheritanceFields;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && yyruleno>=0
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ }
+#endif /* NDEBUG */
+
+ /* Silence complaints from purify about yygotominor being uninitialized
+ ** in some cases when it is copied into the stack after the following
+ ** switch. yygotominor is uninitialized when a rule reduces that does
+ ** not set the value of its left-hand side nonterminal. Leaving the
+ ** value of the nonterminal uninitialized is utterly harmless as long
+ ** as the value is never used. So really the only thing this code
+ ** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
+ */
+ /*memset(&yygotominor, 0, sizeof(yygotominor));*/
+ yygotominor = yyzerominor;
+
+
+ if (parserContext->executeRules)
+ {
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+ case 1: /* cmdlist ::= cmdlist ecmd */
+{parserContext->addQuery(yymsp[0].minor.yy399); DONT_INHERIT_TOKENS("cmdlist");}
+ break;
+ case 2: /* cmdlist ::= ecmd */
+{parserContext->addQuery(yymsp[0].minor.yy399);}
+ break;
+ case 3: /* ecmd ::= SEMI */
+{yygotominor.yy399 = new SqliteEmptyQuery();}
+ break;
+ case 4: /* ecmd ::= explain cmdx SEMI */
+{
+ yygotominor.yy399 = yymsp[-1].minor.yy399;
+ yygotominor.yy399->explain = yymsp[-2].minor.yy225->explain;
+ yygotominor.yy399->queryPlan = yymsp[-2].minor.yy225->queryPlan;
+ delete yymsp[-2].minor.yy225;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 5: /* explain ::= */
+{yygotominor.yy225 = new ParserStubExplain(false, false);}
+ break;
+ case 6: /* explain ::= EXPLAIN */
+{yygotominor.yy225 = new ParserStubExplain(true, false);}
+ break;
+ case 7: /* explain ::= EXPLAIN QUERY PLAN */
+{yygotominor.yy225 = new ParserStubExplain(true, true);}
+ break;
+ case 8: /* cmdx ::= cmd */
+ case 374: /* trigger_cmd ::= update_stmt */ yytestcase(yyruleno==374);
+ case 375: /* trigger_cmd ::= insert_stmt */ yytestcase(yyruleno==375);
+ case 376: /* trigger_cmd ::= delete_stmt */ yytestcase(yyruleno==376);
+ case 377: /* trigger_cmd ::= select_stmt */ yytestcase(yyruleno==377);
+ case 404: /* cmd ::= create_vtab */ yytestcase(yyruleno==404);
+{yygotominor.yy399 = yymsp[0].minor.yy399;}
+ break;
+ case 9: /* cmd ::= BEGIN transtype trans_opt */
+{
+ yygotominor.yy399 = new SqliteBeginTrans(
+ yymsp[-1].minor.yy300->type,
+ yymsp[0].minor.yy300->transactionKw,
+ yymsp[0].minor.yy300->name
+ );
+ delete yymsp[0].minor.yy300;
+ delete yymsp[-1].minor.yy300;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 10: /* trans_opt ::= */
+ case 14: /* transtype ::= */ yytestcase(yyruleno==14);
+{yygotominor.yy300 = new ParserStubTransDetails();}
+ break;
+ case 11: /* trans_opt ::= TRANSACTION */
+{
+ yygotominor.yy300 = new ParserStubTransDetails();
+ yygotominor.yy300->transactionKw = true;
+ }
+ break;
+ case 12: /* trans_opt ::= TRANSACTION nm */
+ case 13: /* trans_opt ::= TRANSACTION ID_TRANS */ yytestcase(yyruleno==13);
+{
+ yygotominor.yy300 = new ParserStubTransDetails();
+ yygotominor.yy300->transactionKw = true;
+ yygotominor.yy300->name = *(yymsp[0].minor.yy211);
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 15: /* transtype ::= DEFERRED */
+{
+ yygotominor.yy300 = new ParserStubTransDetails();
+ yygotominor.yy300->type = SqliteBeginTrans::Type::DEFERRED;
+ }
+ break;
+ case 16: /* transtype ::= IMMEDIATE */
+{
+ yygotominor.yy300 = new ParserStubTransDetails();
+ yygotominor.yy300->type = SqliteBeginTrans::Type::IMMEDIATE;
+ }
+ break;
+ case 17: /* transtype ::= EXCLUSIVE */
+{
+ yygotominor.yy300 = new ParserStubTransDetails();
+ yygotominor.yy300->type = SqliteBeginTrans::Type::EXCLUSIVE;
+ }
+ break;
+ case 18: /* cmd ::= COMMIT trans_opt */
+{
+ yygotominor.yy399 = new SqliteCommitTrans(
+ yymsp[0].minor.yy300->transactionKw,
+ yymsp[0].minor.yy300->name,
+ false
+ );
+ delete yymsp[0].minor.yy300;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 19: /* cmd ::= END trans_opt */
+{
+ yygotominor.yy399 = new SqliteCommitTrans(
+ yymsp[0].minor.yy300->transactionKw,
+ yymsp[0].minor.yy300->name,
+ true
+ );
+ delete yymsp[0].minor.yy300;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 20: /* cmd ::= ROLLBACK trans_opt */
+{
+ yygotominor.yy399 = new SqliteRollback(
+ yymsp[0].minor.yy300->transactionKw,
+ yymsp[0].minor.yy300->name
+ );
+ delete yymsp[0].minor.yy300;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 21: /* savepoint_opt ::= SAVEPOINT */
+ case 37: /* ifnotexists ::= IF NOT EXISTS */ yytestcase(yyruleno==37);
+ case 86: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==86);
+ case 108: /* tconscomma ::= COMMA */ yytestcase(yyruleno==108);
+ case 130: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==130);
+ case 304: /* not_opt ::= NOT */ yytestcase(yyruleno==304);
+ case 320: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==320);
+ case 386: /* database_kw_opt ::= DATABASE */ yytestcase(yyruleno==386);
+ case 402: /* kwcolumn_opt ::= */ yytestcase(yyruleno==402);
+{yygotominor.yy237 = new bool(true);}
+ break;
+ case 22: /* savepoint_opt ::= */
+ case 36: /* ifnotexists ::= */ yytestcase(yyruleno==36);
+ case 85: /* autoinc ::= */ yytestcase(yyruleno==85);
+ case 109: /* tconscomma ::= */ yytestcase(yyruleno==109);
+ case 131: /* ifexists ::= */ yytestcase(yyruleno==131);
+ case 303: /* not_opt ::= */ yytestcase(yyruleno==303);
+ case 321: /* uniqueflag ::= */ yytestcase(yyruleno==321);
+ case 387: /* database_kw_opt ::= */ yytestcase(yyruleno==387);
+ case 403: /* kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==403);
+{yygotominor.yy237 = new bool(false);}
+ break;
+ case 23: /* cmd ::= SAVEPOINT nm */
+{
+ yygotominor.yy399 = new SqliteSavepoint(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 24: /* cmd ::= RELEASE savepoint_opt nm */
+{
+ yygotominor.yy399 = new SqliteRelease(*(yymsp[-1].minor.yy237), *(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 25: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ case 26: /* cmd ::= SAVEPOINT ID_TRANS */ yytestcase(yyruleno==26);
+{
+ yygotominor.yy399 = new SqliteRollback(
+ yymsp[-3].minor.yy300->transactionKw,
+ *(yymsp[-1].minor.yy237),
+ *(yymsp[0].minor.yy211)
+ );
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[-3].minor.yy300;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 27: /* cmd ::= RELEASE savepoint_opt ID_TRANS */
+ case 28: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt ID_TRANS */ yytestcase(yyruleno==28);
+{ yy_destructor(yypParser,178,&yymsp[-1].minor);
+}
+ break;
+ case 29: /* cmd ::= CREATE temp TABLE ifnotexists fullname LP columnlist conslist_opt RP table_options */
+{
+ yygotominor.yy399 = new SqliteCreateTable(
+ *(yymsp[-8].minor.yy376),
+ *(yymsp[-6].minor.yy237),
+ yymsp[-5].minor.yy66->name1,
+ yymsp[-5].minor.yy66->name2,
+ *(yymsp[-3].minor.yy118),
+ *(yymsp[-2].minor.yy87),
+ *(yymsp[0].minor.yy211)
+ );
+ delete yymsp[-6].minor.yy237;
+ delete yymsp[-8].minor.yy376;
+ delete yymsp[-3].minor.yy118;
+ delete yymsp[-2].minor.yy87;
+ delete yymsp[-5].minor.yy66;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 30: /* cmd ::= CREATE temp TABLE ifnotexists fullname AS select */
+{
+ yygotominor.yy399 = new SqliteCreateTable(
+ *(yymsp[-5].minor.yy376),
+ *(yymsp[-3].minor.yy237),
+ yymsp[-2].minor.yy66->name1,
+ yymsp[-2].minor.yy66->name2,
+ yymsp[0].minor.yy123
+ );
+ delete yymsp[-3].minor.yy237;
+ delete yymsp[-5].minor.yy376;
+ delete yymsp[-2].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 31: /* cmd ::= CREATE temp TABLE ifnotexists nm DOT ID_TAB_NEW */
+ case 133: /* cmd ::= CREATE temp VIEW ifnotexists nm DOT ID_VIEW_NEW */ yytestcase(yyruleno==133);
+ case 357: /* cmd ::= CREATE temp TRIGGER ifnotexists nm DOT ID_TRIG_NEW */ yytestcase(yyruleno==357);
+{ yy_destructor(yypParser,179,&yymsp[-5].minor);
+ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 32: /* cmd ::= CREATE temp TABLE ifnotexists ID_DB|ID_TAB_NEW */
+ case 134: /* cmd ::= CREATE temp VIEW ifnotexists ID_DB|ID_VIEW_NEW */ yytestcase(yyruleno==134);
+ case 358: /* cmd ::= CREATE temp TRIGGER ifnotexists ID_DB|ID_TRIG_NEW */ yytestcase(yyruleno==358);
+{ yy_destructor(yypParser,179,&yymsp[-3].minor);
+}
+ break;
+ case 33: /* table_options ::= */
+ case 185: /* dbnm ::= */ yytestcase(yyruleno==185);
+ case 328: /* collate ::= */ yytestcase(yyruleno==328);
+ case 411: /* vtabarg ::= */ yytestcase(yyruleno==411);
+ case 415: /* anylist ::= */ yytestcase(yyruleno==415);
+{yygotominor.yy211 = new QString();}
+ break;
+ case 34: /* table_options ::= WITHOUT nm */
+ case 35: /* table_options ::= WITHOUT CTX_ROWID_KW */ yytestcase(yyruleno==35);
+{
+ if (yymsp[0].minor.yy211->toLower() != "rowid")
+ parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(yymsp[0].minor.yy211)));
+
+ yygotominor.yy211 = yymsp[0].minor.yy211;
+ }
+ break;
+ case 38: /* temp ::= TEMP */
+{yygotominor.yy376 = new int( (yymsp[0].minor.yy0->value.length() > 4) ? 2 : 1 );}
+ break;
+ case 39: /* temp ::= */
+ case 154: /* distinct ::= */ yytestcase(yyruleno==154);
+{yygotominor.yy376 = new int(0);}
+ break;
+ case 40: /* columnlist ::= columnlist COMMA column */
+{
+ yymsp[-2].minor.yy118->append(yymsp[0].minor.yy425);
+ yygotominor.yy118 = yymsp[-2].minor.yy118;
+ DONT_INHERIT_TOKENS("columnlist");
+ }
+ break;
+ case 41: /* columnlist ::= column */
+{
+ yygotominor.yy118 = new ParserCreateTableColumnList();
+ yygotominor.yy118->append(yymsp[0].minor.yy425);
+ }
+ break;
+ case 42: /* column ::= columnid type carglist */
+{
+ yygotominor.yy425 = new SqliteCreateTable::Column(*(yymsp[-2].minor.yy211), yymsp[-1].minor.yy299, *(yymsp[0].minor.yy449));
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy449;
+ objectForTokens = yygotominor.yy425;
+ }
+ break;
+ case 43: /* columnid ::= nm */
+ case 44: /* columnid ::= ID_COL_NEW */ yytestcase(yyruleno==44);
+ case 47: /* nm ::= id */ yytestcase(yyruleno==47);
+ case 55: /* typename ::= ids */ yytestcase(yyruleno==55);
+ case 186: /* dbnm ::= DOT nm */ yytestcase(yyruleno==186);
+ case 329: /* collate ::= COLLATE ids */ yytestcase(yyruleno==329);
+ case 330: /* collate ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==330);
+{yygotominor.yy211 = yymsp[0].minor.yy211;}
+ break;
+ case 45: /* id ::= ID */
+{
+ yygotominor.yy211 = new QString(
+ stripObjName(
+ yymsp[0].minor.yy0->value,
+ parserContext->dialect
+ )
+ );
+ }
+ break;
+ case 46: /* ids ::= ID|STRING */
+ case 49: /* nm ::= JOIN_KW */ yytestcase(yyruleno==49);
+{yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value);}
+ break;
+ case 48: /* nm ::= STRING */
+{yygotominor.yy211 = new QString(stripString(yymsp[0].minor.yy0->value));}
+ break;
+ case 50: /* type ::= */
+{yygotominor.yy299 = nullptr;}
+ break;
+ case 51: /* type ::= typetoken */
+{yygotominor.yy299 = yymsp[0].minor.yy299;}
+ break;
+ case 52: /* typetoken ::= typename */
+{
+ yygotominor.yy299 = new SqliteColumnType(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy299;
+ }
+ break;
+ case 53: /* typetoken ::= typename LP signed RP */
+{
+ yygotominor.yy299 = new SqliteColumnType(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21));
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-1].minor.yy21;
+ objectForTokens = yygotominor.yy299;
+ }
+ break;
+ case 54: /* typetoken ::= typename LP signed COMMA signed RP */
+{
+ yygotominor.yy299 = new SqliteColumnType(*(yymsp[-5].minor.yy211), *(yymsp[-3].minor.yy21), *(yymsp[-1].minor.yy21));
+ delete yymsp[-5].minor.yy211;
+ delete yymsp[-3].minor.yy21;
+ delete yymsp[-1].minor.yy21;
+ objectForTokens = yygotominor.yy299;
+ }
+ break;
+ case 56: /* typename ::= typename ids */
+ case 57: /* typename ::= ID_COL_TYPE */ yytestcase(yyruleno==57);
+{
+ yymsp[-1].minor.yy211->append(" " + *(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ yygotominor.yy211 = yymsp[-1].minor.yy211;
+ }
+ break;
+ case 58: /* signed ::= plus_num */
+ case 59: /* signed ::= minus_num */ yytestcase(yyruleno==59);
+ case 343: /* nmnum ::= plus_num */ yytestcase(yyruleno==343);
+ case 348: /* plus_num ::= PLUS number */ yytestcase(yyruleno==348);
+ case 349: /* plus_num ::= number */ yytestcase(yyruleno==349);
+{yygotominor.yy21 = yymsp[0].minor.yy21;}
+ break;
+ case 60: /* carglist ::= carglist ccons */
+{
+ yymsp[-1].minor.yy449->append(yymsp[0].minor.yy4);
+ yygotominor.yy449 = yymsp[-1].minor.yy449;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+ break;
+ case 61: /* carglist ::= */
+{yygotominor.yy449 = new ParserCreateTableColumnConstraintList();}
+ break;
+ case 62: /* ccons ::= CONSTRAINT nm */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefNameOnly(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 63: /* ccons ::= DEFAULT term */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21));
+ delete yymsp[0].minor.yy21;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 64: /* ccons ::= DEFAULT LP expr RP */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefExpr(yymsp[-1].minor.yy490);
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 65: /* ccons ::= DEFAULT PLUS term */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), false);
+ delete yymsp[0].minor.yy21;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 66: /* ccons ::= DEFAULT MINUS term */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefTerm(*(yymsp[0].minor.yy21), true);
+ delete yymsp[0].minor.yy21;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 67: /* ccons ::= DEFAULT id */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefId(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 68: /* ccons ::= DEFAULT CTIME_KW */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefCTime(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 69: /* ccons ::= NULL onconf */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initNull(*(yymsp[0].minor.yy30));
+ delete yymsp[0].minor.yy30;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 70: /* ccons ::= NOT NULL onconf */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initNotNull(*(yymsp[0].minor.yy30));
+ delete yymsp[0].minor.yy30;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 71: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initPk(*(yymsp[-2].minor.yy226), *(yymsp[-1].minor.yy30), *(yymsp[0].minor.yy237));
+ delete yymsp[-2].minor.yy226;
+ delete yymsp[0].minor.yy237;
+ delete yymsp[-1].minor.yy30;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 72: /* ccons ::= UNIQUE onconf */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initUnique(*(yymsp[0].minor.yy30));
+ delete yymsp[0].minor.yy30;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 73: /* ccons ::= CHECK LP expr RP */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initCheck(yymsp[-1].minor.yy490);
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 74: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initFk(*(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy139), *(yymsp[0].minor.yy108));
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy108;
+ delete yymsp[-1].minor.yy139;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 75: /* ccons ::= defer_subclause */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initDefer(yymsp[0].minor.yy131->initially, yymsp[0].minor.yy131->deferrable);
+ delete yymsp[0].minor.yy131;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 76: /* ccons ::= COLLATE ids */
+ case 77: /* ccons ::= CONSTRAINT ID_CONSTR */ yytestcase(yyruleno==77);
+ case 78: /* ccons ::= COLLATE ID_COLLATE */ yytestcase(yyruleno==78);
+ case 79: /* ccons ::= REFERENCES ID_TAB */ yytestcase(yyruleno==79);
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initColl(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy4;
+ }
+ break;
+ case 80: /* ccons ::= CHECK LP RP */
+{
+ yygotominor.yy4 = new SqliteCreateTable::Column::Constraint();
+ yygotominor.yy4->initCheck();
+ objectForTokens = yygotominor.yy4;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 81: /* term ::= NULL */
+{
+ yygotominor.yy21 = new QVariant();
+ }
+ break;
+ case 82: /* term ::= INTEGER */
+{
+ int base = 10;
+ if (yymsp[0].minor.yy0->value.startsWith("0x", Qt::CaseInsensitive))
+ base = 16;
+
+ yygotominor.yy21 = new QVariant(yymsp[0].minor.yy0->value.toLongLong(nullptr, base));
+ }
+ break;
+ case 83: /* term ::= FLOAT */
+{
+ yygotominor.yy21 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());
+ }
+ break;
+ case 84: /* term ::= STRING|BLOB */
+ case 345: /* nmnum ::= ON */ yytestcase(yyruleno==345);
+ case 346: /* nmnum ::= DELETE */ yytestcase(yyruleno==346);
+ case 347: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==347);
+{yygotominor.yy21 = new QVariant(yymsp[0].minor.yy0->value);}
+ break;
+ case 87: /* refargs ::= */
+{yygotominor.yy108 = new ParserFkConditionList();}
+ break;
+ case 88: /* refargs ::= refargs refarg */
+{
+ yymsp[-1].minor.yy108->append(yymsp[0].minor.yy271);
+ yygotominor.yy108 = yymsp[-1].minor.yy108;
+ DONT_INHERIT_TOKENS("refargs");
+ }
+ break;
+ case 89: /* refarg ::= MATCH nm */
+{
+ yygotominor.yy271 = new SqliteForeignKey::Condition(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 90: /* refarg ::= ON INSERT refact */
+{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;}
+ break;
+ case 91: /* refarg ::= ON DELETE refact */
+{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;}
+ break;
+ case 92: /* refarg ::= ON UPDATE refact */
+ case 93: /* refarg ::= MATCH ID_FK_MATCH */ yytestcase(yyruleno==93);
+{yygotominor.yy271 = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(yymsp[0].minor.yy312)); delete yymsp[0].minor.yy312;}
+ break;
+ case 94: /* refact ::= SET NULL */
+{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);}
+ break;
+ case 95: /* refact ::= SET DEFAULT */
+{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);}
+ break;
+ case 96: /* refact ::= CASCADE */
+{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);}
+ break;
+ case 97: /* refact ::= RESTRICT */
+{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);}
+ break;
+ case 98: /* refact ::= NO ACTION */
+{yygotominor.yy312 = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);}
+ break;
+ case 99: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+{
+ yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(yymsp[0].minor.yy498));
+ delete yymsp[0].minor.yy498;
+ }
+ break;
+ case 100: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+{
+ yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(yymsp[0].minor.yy498));
+ delete yymsp[0].minor.yy498;
+ }
+ break;
+ case 101: /* init_deferred_pred_opt ::= */
+{yygotominor.yy498 = new SqliteInitially(SqliteInitially::null);}
+ break;
+ case 102: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+{yygotominor.yy498 = new SqliteInitially(SqliteInitially::DEFERRED);}
+ break;
+ case 103: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+{yygotominor.yy498 = new SqliteInitially(SqliteInitially::IMMEDIATE);}
+ break;
+ case 104: /* conslist_opt ::= */
+{yygotominor.yy87 = new ParserCreateTableConstraintList();}
+ break;
+ case 105: /* conslist_opt ::= COMMA conslist */
+{yygotominor.yy87 = yymsp[0].minor.yy87;}
+ break;
+ case 106: /* conslist ::= conslist tconscomma tcons */
+{
+ yymsp[0].minor.yy8->afterComma = *(yymsp[-1].minor.yy237);
+ yymsp[-2].minor.yy87->append(yymsp[0].minor.yy8);
+ yygotominor.yy87 = yymsp[-2].minor.yy87;
+ delete yymsp[-1].minor.yy237;
+ DONT_INHERIT_TOKENS("conslist");
+ }
+ break;
+ case 107: /* conslist ::= tcons */
+{
+ yygotominor.yy87 = new ParserCreateTableConstraintList();
+ yygotominor.yy87->append(yymsp[0].minor.yy8);
+ }
+ break;
+ case 110: /* tcons ::= CONSTRAINT nm */
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initNameOnly(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy8;
+ }
+ break;
+ case 111: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initPk(*(yymsp[-3].minor.yy139), *(yymsp[-2].minor.yy237), *(yymsp[0].minor.yy30));
+ delete yymsp[-2].minor.yy237;
+ delete yymsp[0].minor.yy30;
+ delete yymsp[-3].minor.yy139;
+ objectForTokens = yygotominor.yy8;
+ }
+ break;
+ case 112: /* tcons ::= UNIQUE LP idxlist RP onconf */
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initUnique(*(yymsp[-2].minor.yy139), *(yymsp[0].minor.yy30));
+ delete yymsp[0].minor.yy30;
+ delete yymsp[-2].minor.yy139;
+ objectForTokens = yygotominor.yy8;
+ }
+ break;
+ case 113: /* tcons ::= CHECK LP expr RP onconf */
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initCheck(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy30));
+ objectForTokens = yygotominor.yy8;
+ }
+ break;
+ case 114: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
+ case 115: /* tcons ::= CONSTRAINT ID_CONSTR */ yytestcase(yyruleno==115);
+ case 116: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES ID_TAB */ yytestcase(yyruleno==116);
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initFk(
+ *(yymsp[-6].minor.yy139),
+ *(yymsp[-3].minor.yy211),
+ *(yymsp[-2].minor.yy139),
+ *(yymsp[-1].minor.yy108),
+ yymsp[0].minor.yy131->initially,
+ yymsp[0].minor.yy131->deferrable
+ );
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-1].minor.yy108;
+ delete yymsp[0].minor.yy131;
+ delete yymsp[-2].minor.yy139;
+ delete yymsp[-6].minor.yy139;
+ objectForTokens = yygotominor.yy8;
+ }
+ break;
+ case 117: /* tcons ::= CHECK LP RP onconf */
+{
+ yygotominor.yy8 = new SqliteCreateTable::Constraint();
+ yygotominor.yy8->initCheck();
+ objectForTokens = yygotominor.yy8;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ yy_destructor(yypParser,200,&yymsp[0].minor);
+}
+ break;
+ case 118: /* defer_subclause_opt ::= */
+{yygotominor.yy131 = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);}
+ break;
+ case 119: /* defer_subclause_opt ::= defer_subclause */
+{yygotominor.yy131 = yymsp[0].minor.yy131;}
+ break;
+ case 120: /* onconf ::= */
+ case 122: /* orconf ::= */ yytestcase(yyruleno==122);
+{yygotominor.yy30 = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+ break;
+ case 121: /* onconf ::= ON CONFLICT resolvetype */
+ case 123: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==123);
+{yygotominor.yy30 = yymsp[0].minor.yy30;}
+ break;
+ case 124: /* resolvetype ::= raisetype */
+ case 125: /* resolvetype ::= IGNORE */ yytestcase(yyruleno==125);
+ case 126: /* resolvetype ::= REPLACE */ yytestcase(yyruleno==126);
+{yygotominor.yy30 = new SqliteConflictAlgo(sqliteConflictAlgo(yymsp[0].minor.yy0->value));}
+ break;
+ case 127: /* cmd ::= DROP TABLE ifexists fullname */
+{
+ yygotominor.yy399 = new SqliteDropTable(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2);
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[0].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 128: /* cmd ::= DROP TABLE ifexists nm DOT ID_TAB */
+ case 129: /* cmd ::= DROP TABLE ifexists ID_DB|ID_TAB */ yytestcase(yyruleno==129);
+ case 136: /* cmd ::= DROP VIEW ifexists nm DOT ID_VIEW */ yytestcase(yyruleno==136);
+ case 137: /* cmd ::= DROP VIEW ifexists ID_DB|ID_VIEW */ yytestcase(yyruleno==137);
+ case 178: /* singlesrc ::= nm DOT ID_TAB */ yytestcase(yyruleno==178);
+ case 179: /* singlesrc ::= ID_DB|ID_TAB */ yytestcase(yyruleno==179);
+ case 180: /* singlesrc ::= nm DOT ID_VIEW */ yytestcase(yyruleno==180);
+ case 181: /* singlesrc ::= ID_DB|ID_VIEW */ yytestcase(yyruleno==181);
+ case 297: /* exprx ::= nm DOT ID_TAB|ID_COL */ yytestcase(yyruleno==297);
+ case 318: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm DOT ID_IDX_NEW */ yytestcase(yyruleno==318);
+ case 319: /* cmd ::= CREATE uniqueflag INDEX ifnotexists ID_DB|ID_IDX_NEW */ yytestcase(yyruleno==319);
+ case 332: /* cmd ::= DROP INDEX ifexists nm DOT ID_IDX */ yytestcase(yyruleno==332);
+ case 333: /* cmd ::= DROP INDEX ifexists ID_DB|ID_IDX */ yytestcase(yyruleno==333);
+ case 341: /* cmd ::= PRAGMA nm DOT ID_PRAGMA */ yytestcase(yyruleno==341);
+ case 342: /* cmd ::= PRAGMA ID_DB|ID_PRAGMA */ yytestcase(yyruleno==342);
+ case 380: /* cmd ::= DROP TRIGGER ifexists nm DOT ID_TRIG */ yytestcase(yyruleno==380);
+ case 381: /* cmd ::= DROP TRIGGER ifexists ID_DB|ID_TRIG */ yytestcase(yyruleno==381);
+ case 391: /* cmd ::= REINDEX nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==391);
+ case 392: /* cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==392);
+ case 395: /* cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX */ yytestcase(yyruleno==395);
+ case 396: /* cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB */ yytestcase(yyruleno==396);
+ case 400: /* cmd ::= ALTER TABLE nm DOT ID_TAB */ yytestcase(yyruleno==400);
+ case 401: /* cmd ::= ALTER TABLE ID_DB|ID_TAB */ yytestcase(yyruleno==401);
+ case 407: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm DOT ID_TAB_NEW */ yytestcase(yyruleno==407);
+ case 408: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists ID_DB|ID_TAB_NEW */ yytestcase(yyruleno==408);
+{ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 132: /* cmd ::= CREATE temp VIEW ifnotexists fullname AS select */
+{
+ yygotominor.yy399 = new SqliteCreateView(*(yymsp[-5].minor.yy376), *(yymsp[-3].minor.yy237), yymsp[-2].minor.yy66->name1, yymsp[-2].minor.yy66->name2, yymsp[0].minor.yy123);
+ delete yymsp[-5].minor.yy376;
+ delete yymsp[-3].minor.yy237;
+ delete yymsp[-2].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 135: /* cmd ::= DROP VIEW ifexists fullname */
+{
+ yygotominor.yy399 = new SqliteDropView(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2);
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[0].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 138: /* cmd ::= select_stmt */
+ case 214: /* cmd ::= delete_stmt */ yytestcase(yyruleno==214);
+ case 223: /* cmd ::= update_stmt */ yytestcase(yyruleno==223);
+ case 235: /* cmd ::= insert_stmt */ yytestcase(yyruleno==235);
+{
+ yygotominor.yy399 = yymsp[0].minor.yy399;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 139: /* select_stmt ::= select */
+{
+ yygotominor.yy399 = yymsp[0].minor.yy123;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 140: /* select ::= with selectnowith */
+{
+ yygotominor.yy123 = yymsp[0].minor.yy123;
+ yymsp[0].minor.yy123->setWith(yymsp[-1].minor.yy367);
+ objectForTokens = yygotominor.yy123;
+ }
+ break;
+ case 141: /* selectnowith ::= oneselect */
+{
+ yygotominor.yy123 = SqliteSelect::append(yymsp[0].minor.yy468);
+ objectForTokens = yygotominor.yy123;
+ }
+ break;
+ case 142: /* selectnowith ::= selectnowith multiselect_op oneselect */
+{
+ yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, *(yymsp[-1].minor.yy168), yymsp[0].minor.yy468);
+ delete yymsp[-1].minor.yy168;
+ objectForTokens = yygotominor.yy123;
+ }
+ break;
+ case 143: /* selectnowith ::= values */
+{
+ yygotominor.yy123 = SqliteSelect::append(*(yymsp[0].minor.yy416));
+ delete yymsp[0].minor.yy416;
+ objectForTokens = yygotominor.yy123;
+ }
+ break;
+ case 144: /* selectnowith ::= selectnowith COMMA values */
+{
+ yygotominor.yy123 = SqliteSelect::append(yymsp[-2].minor.yy123, SqliteSelect::CompoundOperator::UNION_ALL, *(yymsp[0].minor.yy416));
+ delete yymsp[0].minor.yy416;
+ objectForTokens = yygotominor.yy123;
+ }
+ break;
+ case 145: /* multiselect_op ::= UNION */
+{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);}
+ break;
+ case 146: /* multiselect_op ::= UNION ALL */
+{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);}
+ break;
+ case 147: /* multiselect_op ::= EXCEPT */
+{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);}
+ break;
+ case 148: /* multiselect_op ::= INTERSECT */
+{yygotominor.yy168 = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);}
+ break;
+ case 149: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+{
+ yygotominor.yy468 = new SqliteSelect::Core(
+ *(yymsp[-7].minor.yy376),
+ *(yymsp[-6].minor.yy263),
+ yymsp[-5].minor.yy373,
+ yymsp[-4].minor.yy490,
+ *(yymsp[-3].minor.yy13),
+ yymsp[-2].minor.yy490,
+ *(yymsp[-1].minor.yy495),
+ yymsp[0].minor.yy128
+ );
+ delete yymsp[-6].minor.yy263;
+ delete yymsp[-7].minor.yy376;
+ delete yymsp[-3].minor.yy13;
+ delete yymsp[-1].minor.yy495;
+ objectForTokens = yygotominor.yy468;
+ }
+ break;
+ case 150: /* values ::= VALUES LP nexprlist RP */
+{
+ yygotominor.yy416 = new ParserExprNestedList();
+ yygotominor.yy416->append(*(yymsp[-1].minor.yy13));
+ delete yymsp[-1].minor.yy13;
+ }
+ break;
+ case 151: /* values ::= values COMMA LP exprlist RP */
+{
+ yymsp[-4].minor.yy416->append(*(yymsp[-1].minor.yy13));
+ yygotominor.yy416 = yymsp[-4].minor.yy416;
+ delete yymsp[-1].minor.yy13;
+ DONT_INHERIT_TOKENS("values");
+ }
+ break;
+ case 152: /* distinct ::= DISTINCT */
+{yygotominor.yy376 = new int(1);}
+ break;
+ case 153: /* distinct ::= ALL */
+{yygotominor.yy376 = new int(2);}
+ break;
+ case 155: /* sclp ::= selcollist COMMA */
+{yygotominor.yy263 = yymsp[-1].minor.yy263;}
+ break;
+ case 156: /* sclp ::= */
+{yygotominor.yy263 = new ParserResultColumnList();}
+ break;
+ case 157: /* selcollist ::= sclp expr as */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ yymsp[-1].minor.yy490,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null
+ );
+
+ yymsp[-2].minor.yy263->append(obj);
+ yygotominor.yy263 = yymsp[-2].minor.yy263;
+ delete yymsp[0].minor.yy28;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 158: /* selcollist ::= sclp STAR */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(true);
+
+ yymsp[-1].minor.yy263->append(obj);
+ yygotominor.yy263 = yymsp[-1].minor.yy263;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 159: /* selcollist ::= sclp nm DOT STAR */
+{
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ true,
+ *(yymsp[-2].minor.yy211)
+ );
+ yymsp[-3].minor.yy263->append(obj);
+ yygotominor.yy263 = yymsp[-3].minor.yy263;
+ delete yymsp[-2].minor.yy211;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+ break;
+ case 160: /* selcollist ::= sclp */
+ case 161: /* selcollist ::= sclp ID_TAB DOT STAR */ yytestcase(yyruleno==161);
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy263 = yymsp[0].minor.yy263;
+ }
+ break;
+ case 162: /* as ::= AS nm */
+{
+ yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), true);
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 163: /* as ::= ids */
+ case 164: /* as ::= AS ID_ALIAS */ yytestcase(yyruleno==164);
+ case 165: /* as ::= ID_ALIAS */ yytestcase(yyruleno==165);
+{
+ yygotominor.yy28 = new ParserStubAlias(*(yymsp[0].minor.yy211), false);
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 166: /* as ::= */
+{yygotominor.yy28 = nullptr;}
+ break;
+ case 167: /* from ::= */
+{yygotominor.yy373 = nullptr;}
+ break;
+ case 168: /* from ::= FROM joinsrc */
+{yygotominor.yy373 = yymsp[0].minor.yy373;}
+ break;
+ case 169: /* joinsrc ::= singlesrc seltablist */
+{
+ yygotominor.yy373 = new SqliteSelect::Core::JoinSource(
+ yymsp[-1].minor.yy173,
+ *(yymsp[0].minor.yy359)
+ );
+ delete yymsp[0].minor.yy359;
+ objectForTokens = yygotominor.yy373;
+ }
+ break;
+ case 170: /* joinsrc ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy373 = new SqliteSelect::Core::JoinSource();
+ objectForTokens = yygotominor.yy373;
+ }
+ break;
+ case 171: /* seltablist ::= seltablist joinop singlesrc joinconstr_opt */
+{
+ SqliteSelect::Core::JoinSourceOther* src =
+ new SqliteSelect::Core::JoinSourceOther(yymsp[-2].minor.yy473, yymsp[-1].minor.yy173, yymsp[0].minor.yy117);
+
+ yymsp[-3].minor.yy359->append(src);
+ yygotominor.yy359 = yymsp[-3].minor.yy359;
+ objectForTokens = src;
+ DONT_INHERIT_TOKENS("seltablist");
+ }
+ break;
+ case 172: /* seltablist ::= */
+{
+ yygotominor.yy359 = new ParserOtherSourceList();
+ }
+ break;
+ case 173: /* singlesrc ::= nm dbnm as indexed_opt */
+{
+ yygotominor.yy173 = new SqliteSelect::Core::SingleSource(
+ *(yymsp[-3].minor.yy211),
+ *(yymsp[-2].minor.yy211),
+ yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->asKw : false,
+ yymsp[-1].minor.yy28 ? yymsp[-1].minor.yy28->name : QString::null,
+ yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->notIndexedKw : false,
+ yymsp[0].minor.yy472 ? yymsp[0].minor.yy472->indexedBy : QString::null
+ );
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[-1].minor.yy28;
+ if (yymsp[0].minor.yy472)
+ delete yymsp[0].minor.yy472;
+ objectForTokens = yygotominor.yy173;
+ }
+ break;
+ case 174: /* singlesrc ::= LP select RP as */
+{
+ yygotominor.yy173 = new SqliteSelect::Core::SingleSource(
+ yymsp[-2].minor.yy123,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null
+ );
+ delete yymsp[0].minor.yy28;
+ objectForTokens = yygotominor.yy173;
+ }
+ break;
+ case 175: /* singlesrc ::= LP joinsrc RP as */
+{
+ yygotominor.yy173 = new SqliteSelect::Core::SingleSource(
+ yymsp[-2].minor.yy373,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->asKw : false,
+ yymsp[0].minor.yy28 ? yymsp[0].minor.yy28->name : QString::null
+ );
+ delete yymsp[0].minor.yy28;
+ objectForTokens = yygotominor.yy173;
+ }
+ break;
+ case 176: /* singlesrc ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy173 = new SqliteSelect::Core::SingleSource();
+ objectForTokens = yygotominor.yy173;
+ }
+ break;
+ case 177: /* singlesrc ::= nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy173 = new SqliteSelect::Core::SingleSource();
+ yygotominor.yy173->database = *(yymsp[-1].minor.yy211);
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy173;
+ }
+ break;
+ case 182: /* joinconstr_opt ::= ON expr */
+{
+ yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(yymsp[0].minor.yy490);
+ objectForTokens = yygotominor.yy117;
+ }
+ break;
+ case 183: /* joinconstr_opt ::= USING LP inscollist RP */
+{
+ yygotominor.yy117 = new SqliteSelect::Core::JoinConstraint(*(yymsp[-1].minor.yy445));
+ delete yymsp[-1].minor.yy445;
+ objectForTokens = yygotominor.yy117;
+ }
+ break;
+ case 184: /* joinconstr_opt ::= */
+{yygotominor.yy117 = nullptr;}
+ break;
+ case 187: /* fullname ::= nm dbnm */
+{
+ yygotominor.yy66 = new ParserFullName();
+ yygotominor.yy66->name1 = *(yymsp[-1].minor.yy211);
+ yygotominor.yy66->name2 = *(yymsp[0].minor.yy211);
+ delete yymsp[-1].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 188: /* joinop ::= COMMA */
+{
+ yygotominor.yy473 = new SqliteSelect::Core::JoinOp(true);
+ objectForTokens = yygotominor.yy473;
+ }
+ break;
+ case 189: /* joinop ::= JOIN */
+{
+ yygotominor.yy473 = new SqliteSelect::Core::JoinOp(false);
+ objectForTokens = yygotominor.yy473;
+ }
+ break;
+ case 190: /* joinop ::= JOIN_KW JOIN */
+{
+ yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy473;
+ }
+ break;
+ case 191: /* joinop ::= JOIN_KW nm JOIN */
+{
+ yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-2].minor.yy0->value, *(yymsp[-1].minor.yy211));
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy473;
+ }
+ break;
+ case 192: /* joinop ::= JOIN_KW nm nm JOIN */
+ case 193: /* joinop ::= ID_JOIN_OPTS */ yytestcase(yyruleno==193);
+{
+ yygotominor.yy473 = new SqliteSelect::Core::JoinOp(yymsp[-3].minor.yy0->value, *(yymsp[-2].minor.yy211), *(yymsp[-1].minor.yy211));
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ objectForTokens = yygotominor.yy473;
+ }
+ break;
+ case 194: /* indexed_opt ::= */
+{yygotominor.yy472 = nullptr;}
+ break;
+ case 195: /* indexed_opt ::= INDEXED BY nm */
+{
+ yygotominor.yy472 = new ParserIndexedBy(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 196: /* indexed_opt ::= NOT INDEXED */
+ case 197: /* indexed_opt ::= INDEXED BY ID_IDX */ yytestcase(yyruleno==197);
+{yygotominor.yy472 = new ParserIndexedBy(true);}
+ break;
+ case 198: /* orderby_opt ::= */
+{yygotominor.yy495 = new ParserOrderByList();}
+ break;
+ case 199: /* orderby_opt ::= ORDER BY sortlist */
+{yygotominor.yy495 = yymsp[0].minor.yy495;}
+ break;
+ case 200: /* sortlist ::= sortlist COMMA expr sortorder */
+{
+ SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226));
+ yymsp[-3].minor.yy495->append(obj);
+ yygotominor.yy495 = yymsp[-3].minor.yy495;
+ delete yymsp[0].minor.yy226;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sortlist");
+ }
+ break;
+ case 201: /* sortlist ::= expr sortorder */
+{
+ SqliteOrderBy* obj = new SqliteOrderBy(yymsp[-1].minor.yy490, *(yymsp[0].minor.yy226));
+ yygotominor.yy495 = new ParserOrderByList();
+ yygotominor.yy495->append(obj);
+ delete yymsp[0].minor.yy226;
+ objectForTokens = obj;
+ }
+ break;
+ case 202: /* sortorder ::= ASC */
+{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::ASC);}
+ break;
+ case 203: /* sortorder ::= DESC */
+{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::DESC);}
+ break;
+ case 204: /* sortorder ::= */
+{yygotominor.yy226 = new SqliteSortOrder(SqliteSortOrder::null);}
+ break;
+ case 205: /* groupby_opt ::= */
+ case 313: /* exprlist ::= */ yytestcase(yyruleno==313);
+{yygotominor.yy13 = new ParserExprList();}
+ break;
+ case 206: /* groupby_opt ::= GROUP BY nexprlist */
+ case 312: /* exprlist ::= nexprlist */ yytestcase(yyruleno==312);
+{yygotominor.yy13 = yymsp[0].minor.yy13;}
+ break;
+ case 207: /* groupby_opt ::= GROUP BY */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy13 = new ParserExprList();
+ }
+ break;
+ case 208: /* having_opt ::= */
+ case 220: /* where_opt ::= */ yytestcase(yyruleno==220);
+ case 309: /* case_else ::= */ yytestcase(yyruleno==309);
+ case 311: /* case_operand ::= */ yytestcase(yyruleno==311);
+ case 369: /* when_clause ::= */ yytestcase(yyruleno==369);
+ case 384: /* key_opt ::= */ yytestcase(yyruleno==384);
+{yygotominor.yy490 = nullptr;}
+ break;
+ case 209: /* having_opt ::= HAVING expr */
+ case 221: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==221);
+ case 301: /* expr ::= exprx */ yytestcase(yyruleno==301);
+ case 308: /* case_else ::= ELSE expr */ yytestcase(yyruleno==308);
+ case 310: /* case_operand ::= exprx */ yytestcase(yyruleno==310);
+ case 370: /* when_clause ::= WHEN expr */ yytestcase(yyruleno==370);
+ case 385: /* key_opt ::= KEY expr */ yytestcase(yyruleno==385);
+{yygotominor.yy490 = yymsp[0].minor.yy490;}
+ break;
+ case 210: /* limit_opt ::= */
+{yygotominor.yy128 = nullptr;}
+ break;
+ case 211: /* limit_opt ::= LIMIT expr */
+{
+ yygotominor.yy128 = new SqliteLimit(yymsp[0].minor.yy490);
+ objectForTokens = yygotominor.yy128;
+ }
+ break;
+ case 212: /* limit_opt ::= LIMIT expr OFFSET expr */
+{
+ yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, true);
+ objectForTokens = yygotominor.yy128;
+ }
+ break;
+ case 213: /* limit_opt ::= LIMIT expr COMMA expr */
+{
+ yygotominor.yy128 = new SqliteLimit(yymsp[-2].minor.yy490, yymsp[0].minor.yy490, false);
+ objectForTokens = yygotominor.yy128;
+ }
+ break;
+ case 215: /* delete_stmt ::= with DELETE FROM fullname indexed_opt where_opt */
+{
+ if (yymsp[-1].minor.yy472)
+ {
+ if (!yymsp[-1].minor.yy472->indexedBy.isNull())
+ {
+ yygotominor.yy399 = new SqliteDelete(
+ yymsp[-2].minor.yy66->name1,
+ yymsp[-2].minor.yy66->name2,
+ yymsp[-1].minor.yy472->indexedBy,
+ yymsp[0].minor.yy490,
+ yymsp[-5].minor.yy367
+ );
+ }
+ else
+ {
+ yygotominor.yy399 = new SqliteDelete(
+ yymsp[-2].minor.yy66->name1,
+ yymsp[-2].minor.yy66->name2,
+ yymsp[-1].minor.yy472->notIndexedKw,
+ yymsp[0].minor.yy490,
+ yymsp[-5].minor.yy367
+ );
+ }
+ delete yymsp[-1].minor.yy472;
+ }
+ else
+ {
+ yygotominor.yy399 = new SqliteDelete(
+ yymsp[-2].minor.yy66->name1,
+ yymsp[-2].minor.yy66->name2,
+ false,
+ yymsp[0].minor.yy490,
+ yymsp[-5].minor.yy367
+ );
+ }
+ delete yymsp[-2].minor.yy66;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 216: /* delete_stmt ::= with DELETE FROM */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->with = yymsp[-2].minor.yy367;
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 217: /* delete_stmt ::= with DELETE FROM nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->with = yymsp[-4].minor.yy367;
+ q->database = *(yymsp[-1].minor.yy211);
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ delete yymsp[-1].minor.yy211;
+ }
+ break;
+ case 218: /* delete_stmt ::= with DELETE FROM nm DOT ID_TAB */
+ case 227: /* update_stmt ::= with UPDATE orconf nm DOT ID_TAB */ yytestcase(yyruleno==227);
+{ yy_destructor(yypParser,219,&yymsp[-5].minor);
+ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 219: /* delete_stmt ::= with DELETE FROM ID_DB|ID_TAB */
+ case 228: /* update_stmt ::= with UPDATE orconf ID_DB|ID_TAB */ yytestcase(yyruleno==228);
+{ yy_destructor(yypParser,219,&yymsp[-3].minor);
+}
+ break;
+ case 222: /* where_opt ::= WHERE */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy490 = new SqliteExpr();
+ }
+ break;
+ case 224: /* update_stmt ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
+{
+ yygotominor.yy399 = new SqliteUpdate(
+ *(yymsp[-5].minor.yy30),
+ yymsp[-4].minor.yy66->name1,
+ yymsp[-4].minor.yy66->name2,
+ yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->notIndexedKw : false,
+ yymsp[-3].minor.yy472 ? yymsp[-3].minor.yy472->indexedBy : QString::null,
+ *(yymsp[-1].minor.yy381),
+ yymsp[0].minor.yy490,
+ yymsp[-7].minor.yy367
+ );
+ delete yymsp[-5].minor.yy30;
+ delete yymsp[-4].minor.yy66;
+ delete yymsp[-1].minor.yy381;
+ if (yymsp[-3].minor.yy472)
+ delete yymsp[-3].minor.yy472;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 225: /* update_stmt ::= with UPDATE orconf */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->with = yymsp[-2].minor.yy367;
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ delete yymsp[0].minor.yy30;
+ }
+ break;
+ case 226: /* update_stmt ::= with UPDATE orconf nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->with = yymsp[-4].minor.yy367;
+ q->database = *(yymsp[-1].minor.yy211);
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ delete yymsp[-2].minor.yy30;
+ delete yymsp[-1].minor.yy211;
+ }
+ break;
+ case 229: /* setlist ::= setlist COMMA nm EQ expr */
+{
+ yymsp[-4].minor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490));
+ yygotominor.yy381 = yymsp[-4].minor.yy381;
+ delete yymsp[-2].minor.yy211;
+ DONT_INHERIT_TOKENS("setlist");
+ }
+ break;
+ case 230: /* setlist ::= nm EQ expr */
+{
+ yygotominor.yy381 = new ParserSetValueList();
+ yygotominor.yy381->append(ParserSetValue(*(yymsp[-2].minor.yy211), yymsp[0].minor.yy490));
+ delete yymsp[-2].minor.yy211;
+ }
+ break;
+ case 231: /* setlist ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy381 = new ParserSetValueList();
+ }
+ break;
+ case 232: /* setlist ::= setlist COMMA */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy381 = yymsp[-1].minor.yy381;
+ }
+ break;
+ case 233: /* setlist ::= setlist COMMA ID_COL */
+ case 234: /* setlist ::= ID_COL */ yytestcase(yyruleno==234);
+{ yy_destructor(yypParser,247,&yymsp[-2].minor);
+}
+ break;
+ case 236: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt select */
+{
+ yygotominor.yy399 = new SqliteInsert(
+ yymsp[-4].minor.yy250->replace,
+ yymsp[-4].minor.yy250->orConflict,
+ yymsp[-2].minor.yy66->name1,
+ yymsp[-2].minor.yy66->name2,
+ *(yymsp[-1].minor.yy445),
+ yymsp[0].minor.yy123,
+ yymsp[-5].minor.yy367
+ );
+ delete yymsp[-2].minor.yy66;
+ delete yymsp[-4].minor.yy250;
+ delete yymsp[-1].minor.yy445;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 237: /* insert_stmt ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
+{
+ yygotominor.yy399 = new SqliteInsert(
+ yymsp[-5].minor.yy250->replace,
+ yymsp[-5].minor.yy250->orConflict,
+ yymsp[-3].minor.yy66->name1,
+ yymsp[-3].minor.yy66->name2,
+ *(yymsp[-2].minor.yy445),
+ yymsp[-6].minor.yy367
+ );
+ delete yymsp[-3].minor.yy66;
+ delete yymsp[-5].minor.yy250;
+ delete yymsp[-2].minor.yy445;
+ // since it's used in trigger:
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 238: /* insert_stmt ::= with insert_cmd INTO */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = yymsp[-1].minor.yy250->replace;
+ q->onConflict = yymsp[-1].minor.yy250->orConflict;
+ q->with = yymsp[-2].minor.yy367;
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ delete yymsp[-1].minor.yy250;
+ }
+ break;
+ case 239: /* insert_stmt ::= with insert_cmd INTO nm DOT */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = yymsp[-3].minor.yy250->replace;
+ q->onConflict = yymsp[-3].minor.yy250->orConflict;
+ q->with = yymsp[-4].minor.yy367;
+ q->database = *(yymsp[-1].minor.yy211);
+ yygotominor.yy399 = q;
+ objectForTokens = yygotominor.yy399;
+ delete yymsp[-3].minor.yy250;
+ delete yymsp[-1].minor.yy211;
+ }
+ break;
+ case 240: /* insert_stmt ::= with insert_cmd INTO ID_DB|ID_TAB */
+{ yy_destructor(yypParser,219,&yymsp[-3].minor);
+ yy_destructor(yypParser,249,&yymsp[-2].minor);
+}
+ break;
+ case 241: /* insert_stmt ::= with insert_cmd INTO nm DOT ID_TAB */
+{ yy_destructor(yypParser,219,&yymsp[-5].minor);
+ yy_destructor(yypParser,249,&yymsp[-4].minor);
+ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 242: /* insert_cmd ::= INSERT orconf */
+{
+ yygotominor.yy250 = new ParserStubInsertOrReplace(false, *(yymsp[0].minor.yy30));
+ delete yymsp[0].minor.yy30;
+ }
+ break;
+ case 243: /* insert_cmd ::= REPLACE */
+{yygotominor.yy250 = new ParserStubInsertOrReplace(true);}
+ break;
+ case 244: /* inscollist_opt ::= */
+{yygotominor.yy445 = new ParserStringList();}
+ break;
+ case 245: /* inscollist_opt ::= LP inscollist RP */
+{yygotominor.yy445 = yymsp[-1].minor.yy445;}
+ break;
+ case 246: /* inscollist ::= inscollist COMMA nm */
+{
+ yymsp[-2].minor.yy445->append(*(yymsp[0].minor.yy211));
+ yygotominor.yy445 = yymsp[-2].minor.yy445;
+ delete yymsp[0].minor.yy211;
+ DONT_INHERIT_TOKENS("inscollist");
+ }
+ break;
+ case 247: /* inscollist ::= nm */
+{
+ yygotominor.yy445 = new ParserStringList();
+ yygotominor.yy445->append(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 248: /* inscollist ::= */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy445 = new ParserStringList();
+ }
+ break;
+ case 249: /* inscollist ::= inscollist COMMA ID_COL */
+ case 250: /* inscollist ::= ID_COL */ yytestcase(yyruleno==250);
+{ yy_destructor(yypParser,243,&yymsp[-2].minor);
+}
+ break;
+ case 251: /* exprx ::= term */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initLiteral(*(yymsp[0].minor.yy21));
+ delete yymsp[0].minor.yy21;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 252: /* exprx ::= CTIME_KW */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initCTime(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 253: /* exprx ::= LP expr RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initSubExpr(yymsp[-1].minor.yy490);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 254: /* exprx ::= id */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 255: /* exprx ::= JOIN_KW */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 256: /* exprx ::= nm DOT nm */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(*(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 257: /* exprx ::= nm DOT nm DOT nm */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(*(yymsp[-4].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-4].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 258: /* exprx ::= VARIABLE */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initBindParam(yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 259: /* exprx ::= expr COLLATE ids */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initCollate(yymsp[-2].minor.yy490, *(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 260: /* exprx ::= CAST LP expr AS typetoken RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initCast(yymsp[-3].minor.yy490, yymsp[-1].minor.yy299);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 261: /* exprx ::= ID LP distinct exprlist RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initFunction(yymsp[-4].minor.yy0->value, *(yymsp[-2].minor.yy376), *(yymsp[-1].minor.yy13));
+ delete yymsp[-2].minor.yy376;
+ delete yymsp[-1].minor.yy13;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 262: /* exprx ::= ID LP STAR RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initFunction(yymsp[-3].minor.yy0->value, true);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 263: /* exprx ::= expr AND expr */
+ case 264: /* exprx ::= expr OR expr */ yytestcase(yyruleno==264);
+ case 265: /* exprx ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==265);
+ case 266: /* exprx ::= expr EQ|NE expr */ yytestcase(yyruleno==266);
+ case 267: /* exprx ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==267);
+ case 268: /* exprx ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==268);
+ case 269: /* exprx ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==269);
+ case 270: /* exprx ::= expr CONCAT expr */ yytestcase(yyruleno==270);
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initBinOp(yymsp[-2].minor.yy490, yymsp[-1].minor.yy0->value, yymsp[0].minor.yy490);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 271: /* exprx ::= expr not_opt likeop expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initLike(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy237), *(yymsp[-1].minor.yy374), yymsp[0].minor.yy490);
+ delete yymsp[-2].minor.yy237;
+ delete yymsp[-1].minor.yy374;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 272: /* exprx ::= expr not_opt likeop expr ESCAPE expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initLike(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-3].minor.yy374), yymsp[-2].minor.yy490, yymsp[0].minor.yy490);
+ delete yymsp[-4].minor.yy237;
+ delete yymsp[-3].minor.yy374;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 273: /* exprx ::= expr ISNULL|NOTNULL */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initNull(yymsp[-1].minor.yy490, yymsp[0].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 274: /* exprx ::= expr NOT NULL */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initNull(yymsp[-2].minor.yy490, "NOT NULL");
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 275: /* exprx ::= expr IS not_opt expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initIs(yymsp[-3].minor.yy490, *(yymsp[-1].minor.yy237), yymsp[0].minor.yy490);
+ delete yymsp[-1].minor.yy237;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 276: /* exprx ::= NOT expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value);
+ }
+ break;
+ case 277: /* exprx ::= BITNOT expr */
+ case 278: /* exprx ::= MINUS expr */ yytestcase(yyruleno==278);
+ case 279: /* exprx ::= PLUS expr */ yytestcase(yyruleno==279);
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initUnaryOp(yymsp[0].minor.yy490, yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 280: /* exprx ::= expr not_opt BETWEEN expr AND expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initBetween(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-2].minor.yy490, yymsp[0].minor.yy490);
+ delete yymsp[-4].minor.yy237;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 281: /* exprx ::= expr not_opt IN LP exprlist RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), *(yymsp[-1].minor.yy13));
+ delete yymsp[-4].minor.yy237;
+ delete yymsp[-1].minor.yy13;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 282: /* exprx ::= LP select RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initSubSelect(yymsp[-1].minor.yy123);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 283: /* exprx ::= expr not_opt IN LP select RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initIn(yymsp[-5].minor.yy490, *(yymsp[-4].minor.yy237), yymsp[-1].minor.yy123);
+ delete yymsp[-4].minor.yy237;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 284: /* exprx ::= expr not_opt IN nm dbnm */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initIn(yymsp[-4].minor.yy490, yymsp[-3].minor.yy237, *(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-3].minor.yy237;
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 285: /* exprx ::= EXISTS LP select RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initExists(yymsp[-1].minor.yy123);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 286: /* exprx ::= CASE case_operand case_exprlist case_else END */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initCase(yymsp[-3].minor.yy490, *(yymsp[-2].minor.yy13), yymsp[-1].minor.yy490);
+ delete yymsp[-2].minor.yy13;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 287: /* exprx ::= RAISE LP IGNORE RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initRaise(yymsp[-1].minor.yy0->value);
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 288: /* exprx ::= RAISE LP raisetype COMMA nm RP */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initRaise(yymsp[-3].minor.yy0->value, *(yymsp[-1].minor.yy211));
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ }
+ break;
+ case 289: /* exprx ::= nm DOT */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(*(yymsp[-1].minor.yy211), QString::null, QString::null);
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 290: /* exprx ::= nm DOT nm DOT */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ yygotominor.yy490->initId(*(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy211), QString::null);
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 291: /* exprx ::= expr not_opt BETWEEN expr */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ delete yymsp[-2].minor.yy237;
+ delete yymsp[-3].minor.yy490;
+ delete yymsp[0].minor.yy490;
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 292: /* exprx ::= CASE case_operand case_exprlist case_else */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ delete yymsp[-1].minor.yy13;
+ delete yymsp[-2].minor.yy490;
+ delete yymsp[0].minor.yy490;
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 293: /* exprx ::= expr not_opt IN LP exprlist */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ delete yymsp[-3].minor.yy237;
+ delete yymsp[0].minor.yy13;
+ delete yymsp[-4].minor.yy490;
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+ break;
+ case 294: /* exprx ::= expr not_opt IN ID_DB */
+{ yy_destructor(yypParser,199,&yymsp[-3].minor);
+}
+ break;
+ case 295: /* exprx ::= expr not_opt IN nm DOT ID_TAB */
+ case 296: /* exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN */ yytestcase(yyruleno==296);
+{ yy_destructor(yypParser,199,&yymsp[-5].minor);
+ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 298: /* exprx ::= nm DOT nm DOT ID_COL */
+{ yy_destructor(yypParser,177,&yymsp[-4].minor);
+ yy_destructor(yypParser,177,&yymsp[-2].minor);
+}
+ break;
+ case 299: /* exprx ::= expr COLLATE ID_COLLATE */
+ case 300: /* exprx ::= RAISE LP raisetype COMMA ID_ERR_MSG RP */ yytestcase(yyruleno==300);
+{ yy_destructor(yypParser,199,&yymsp[-2].minor);
+}
+ break;
+ case 302: /* expr ::= */
+{
+ yygotominor.yy490 = new SqliteExpr();
+ objectForTokens = yygotominor.yy490;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 305: /* likeop ::= LIKE_KW|MATCH */
+{yygotominor.yy374 = new SqliteExpr::LikeOp(SqliteExpr::likeOp(yymsp[0].minor.yy0->value));}
+ break;
+ case 306: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+{
+ yymsp[-4].minor.yy13->append(yymsp[-2].minor.yy490);
+ yymsp[-4].minor.yy13->append(yymsp[0].minor.yy490);
+ yygotominor.yy13 = yymsp[-4].minor.yy13;
+ }
+ break;
+ case 307: /* case_exprlist ::= WHEN expr THEN expr */
+{
+ yygotominor.yy13 = new ParserExprList();
+ yygotominor.yy13->append(yymsp[-2].minor.yy490);
+ yygotominor.yy13->append(yymsp[0].minor.yy490);
+ }
+ break;
+ case 314: /* nexprlist ::= nexprlist COMMA expr */
+{
+ yymsp[-2].minor.yy13->append(yymsp[0].minor.yy490);
+ yygotominor.yy13 = yymsp[-2].minor.yy13;
+ DONT_INHERIT_TOKENS("nexprlist");
+ }
+ break;
+ case 315: /* nexprlist ::= exprx */
+{
+ yygotominor.yy13 = new ParserExprList();
+ yygotominor.yy13->append(yymsp[0].minor.yy490);
+ }
+ break;
+ case 316: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt */
+{
+ yygotominor.yy399 = new SqliteCreateIndex(
+ *(yymsp[-10].minor.yy237),
+ *(yymsp[-8].minor.yy237),
+ *(yymsp[-7].minor.yy211),
+ *(yymsp[-6].minor.yy211),
+ *(yymsp[-4].minor.yy211),
+ *(yymsp[-2].minor.yy139),
+ yymsp[0].minor.yy490
+ );
+ delete yymsp[-8].minor.yy237;
+ delete yymsp[-10].minor.yy237;
+ delete yymsp[-7].minor.yy211;
+ delete yymsp[-6].minor.yy211;
+ delete yymsp[-4].minor.yy211;
+ delete yymsp[-2].minor.yy139;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 317: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON ID_TAB */
+{ yy_destructor(yypParser,177,&yymsp[-3].minor);
+}
+ break;
+ case 322: /* idxlist_opt ::= */
+{yygotominor.yy139 = new ParserIndexedColumnList();}
+ break;
+ case 323: /* idxlist_opt ::= LP idxlist RP */
+{yygotominor.yy139 = yymsp[-1].minor.yy139;}
+ break;
+ case 324: /* idxlist ::= idxlist COMMA idxlist_single */
+{
+ yymsp[-2].minor.yy139->append(yymsp[0].minor.yy90);
+ yygotominor.yy139 = yymsp[-2].minor.yy139;
+ DONT_INHERIT_TOKENS("idxlist");
+ }
+ break;
+ case 325: /* idxlist ::= idxlist_single */
+{
+ yygotominor.yy139 = new ParserIndexedColumnList();
+ yygotominor.yy139->append(yymsp[0].minor.yy90);
+ }
+ break;
+ case 326: /* idxlist_single ::= nm collate sortorder */
+ case 327: /* idxlist_single ::= ID_COL */ yytestcase(yyruleno==327);
+{
+ SqliteIndexedColumn* obj =
+ new SqliteIndexedColumn(
+ *(yymsp[-2].minor.yy211),
+ *(yymsp[-1].minor.yy211),
+ *(yymsp[0].minor.yy226)
+ );
+ yygotominor.yy90 = obj;
+ delete yymsp[0].minor.yy226;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[-1].minor.yy211;
+ objectForTokens = yygotominor.yy90;
+ }
+ break;
+ case 331: /* cmd ::= DROP INDEX ifexists fullname */
+{
+ yygotominor.yy399 = new SqliteDropIndex(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2);
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[0].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 334: /* cmd ::= VACUUM */
+{
+ yygotominor.yy399 = new SqliteVacuum();
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 335: /* cmd ::= VACUUM nm */
+{
+ yygotominor.yy399 = new SqliteVacuum(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 336: /* cmd ::= PRAGMA nm dbnm */
+{
+ yygotominor.yy399 = new SqlitePragma(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-1].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 337: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 339: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ yytestcase(yyruleno==339);
+{
+ yygotominor.yy399 = new SqlitePragma(*(yymsp[-3].minor.yy211), *(yymsp[-2].minor.yy211), *(yymsp[0].minor.yy21), true);
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy21;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 338: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 340: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ yytestcase(yyruleno==340);
+{
+ yygotominor.yy399 = new SqlitePragma(*(yymsp[-4].minor.yy211), *(yymsp[-3].minor.yy211), *(yymsp[-1].minor.yy21), false);
+ delete yymsp[-4].minor.yy211;
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-1].minor.yy21;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 344: /* nmnum ::= nm */
+{
+ yygotominor.yy21 = new QVariant(*(yymsp[0].minor.yy211));
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 350: /* minus_num ::= MINUS number */
+{
+ if (yymsp[0].minor.yy21->type() == QVariant::Double)
+ *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toDouble());
+ else if (yymsp[0].minor.yy21->type() == QVariant::LongLong)
+ *(yymsp[0].minor.yy21) = -(yymsp[0].minor.yy21->toLongLong());
+ else
+ Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong.");
+
+ yygotominor.yy21 = yymsp[0].minor.yy21;
+ }
+ break;
+ case 351: /* number ::= INTEGER */
+{yygotominor.yy21 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toLongLong());}
+ break;
+ case 352: /* number ::= FLOAT */
+{yygotominor.yy21 = new QVariant(QVariant(yymsp[0].minor.yy0->value).toDouble());}
+ break;
+ case 353: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list END */
+{
+ yygotominor.yy399 = new SqliteCreateTrigger(
+ *(yymsp[-13].minor.yy376),
+ *(yymsp[-11].minor.yy237),
+ *(yymsp[-10].minor.yy211),
+ *(yymsp[-9].minor.yy211),
+ *(yymsp[-5].minor.yy211),
+ *(yymsp[-8].minor.yy152),
+ yymsp[-7].minor.yy309,
+ *(yymsp[-4].minor.yy409),
+ yymsp[-3].minor.yy490,
+ *(yymsp[-1].minor.yy214),
+ 3
+ );
+ delete yymsp[-11].minor.yy237;
+ delete yymsp[-13].minor.yy376;
+ delete yymsp[-8].minor.yy152;
+ delete yymsp[-4].minor.yy409;
+ delete yymsp[-10].minor.yy211;
+ delete yymsp[-5].minor.yy211;
+ delete yymsp[-9].minor.yy211;
+ delete yymsp[-1].minor.yy214;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 354: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause */
+{
+ QList<SqliteQuery *> CL;
+
+ yygotominor.yy399 = new SqliteCreateTrigger(
+ *(yymsp[-10].minor.yy376),
+ *(yymsp[-8].minor.yy237),
+ *(yymsp[-7].minor.yy211),
+ *(yymsp[-6].minor.yy211),
+ *(yymsp[-2].minor.yy211),
+ *(yymsp[-5].minor.yy152),
+ yymsp[-4].minor.yy309,
+ *(yymsp[-1].minor.yy409),
+ yymsp[0].minor.yy490,
+ CL,
+ 3
+ );
+ delete yymsp[-8].minor.yy237;
+ delete yymsp[-10].minor.yy376;
+ delete yymsp[-5].minor.yy152;
+ delete yymsp[-1].minor.yy409;
+ delete yymsp[-7].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[-6].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 355: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON nm foreach_clause when_clause BEGIN trigger_cmd_list */
+{
+ yygotominor.yy399 = new SqliteCreateTrigger(
+ *(yymsp[-12].minor.yy376),
+ *(yymsp[-10].minor.yy237),
+ *(yymsp[-9].minor.yy211),
+ *(yymsp[-8].minor.yy211),
+ *(yymsp[-4].minor.yy211),
+ *(yymsp[-7].minor.yy152),
+ yymsp[-6].minor.yy309,
+ *(yymsp[-3].minor.yy409),
+ yymsp[-2].minor.yy490,
+ *(yymsp[0].minor.yy214),
+ 3
+ );
+ delete yymsp[-10].minor.yy237;
+ delete yymsp[-12].minor.yy376;
+ delete yymsp[-7].minor.yy152;
+ delete yymsp[-3].minor.yy409;
+ delete yymsp[-9].minor.yy211;
+ delete yymsp[-4].minor.yy211;
+ delete yymsp[-8].minor.yy211;
+ delete yymsp[0].minor.yy214;
+ objectForTokens = yygotominor.yy399;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 356: /* cmd ::= CREATE temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON ID_TAB */
+{ yy_destructor(yypParser,179,&yymsp[-8].minor);
+ yy_destructor(yypParser,177,&yymsp[-5].minor);
+ yy_destructor(yypParser,262,&yymsp[-3].minor);
+ yy_destructor(yypParser,263,&yymsp[-2].minor);
+}
+ break;
+ case 359: /* trigger_time ::= BEFORE */
+{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);}
+ break;
+ case 360: /* trigger_time ::= AFTER */
+{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);}
+ break;
+ case 361: /* trigger_time ::= INSTEAD OF */
+{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);}
+ break;
+ case 362: /* trigger_time ::= */
+{yygotominor.yy152 = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);}
+ break;
+ case 363: /* trigger_event ::= DELETE */
+{
+ yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE);
+ objectForTokens = yygotominor.yy309;
+ }
+ break;
+ case 364: /* trigger_event ::= INSERT */
+{
+ yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT);
+ objectForTokens = yygotominor.yy309;
+ }
+ break;
+ case 365: /* trigger_event ::= UPDATE */
+{
+ yygotominor.yy309 = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE);
+ objectForTokens = yygotominor.yy309;
+ }
+ break;
+ case 366: /* trigger_event ::= UPDATE OF inscollist */
+{
+ yygotominor.yy309 = new SqliteCreateTrigger::Event(*(yymsp[0].minor.yy445));
+ delete yymsp[0].minor.yy445;
+ objectForTokens = yygotominor.yy309;
+ }
+ break;
+ case 367: /* foreach_clause ::= */
+{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);}
+ break;
+ case 368: /* foreach_clause ::= FOR EACH ROW */
+{yygotominor.yy409 = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);}
+ break;
+ case 371: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+{
+ yymsp[-2].minor.yy214->append(yymsp[-1].minor.yy399);
+ yygotominor.yy214 = yymsp[-2].minor.yy214;
+ DONT_INHERIT_TOKENS("trigger_cmd_list");
+ }
+ break;
+ case 372: /* trigger_cmd_list ::= trigger_cmd SEMI */
+{
+ yygotominor.yy214 = new ParserQueryList();
+ yygotominor.yy214->append(yymsp[-1].minor.yy399);
+ }
+ break;
+ case 373: /* trigger_cmd_list ::= SEMI */
+{
+ yygotominor.yy214 = new ParserQueryList();
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+ break;
+ case 378: /* raisetype ::= ROLLBACK|ABORT|FAIL */
+{yygotominor.yy0 = yymsp[0].minor.yy0;}
+ break;
+ case 379: /* cmd ::= DROP TRIGGER ifexists fullname */
+{
+ yygotominor.yy399 = new SqliteDropTrigger(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy66->name1, yymsp[0].minor.yy66->name2);
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[0].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 382: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+{
+ yygotominor.yy399 = new SqliteAttach(*(yymsp[-4].minor.yy237), yymsp[-3].minor.yy490, yymsp[-1].minor.yy490, yymsp[0].minor.yy490);
+ delete yymsp[-4].minor.yy237;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 383: /* cmd ::= DETACH database_kw_opt expr */
+{
+ yygotominor.yy399 = new SqliteDetach(*(yymsp[-1].minor.yy237), yymsp[0].minor.yy490);
+ delete yymsp[-1].minor.yy237;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 388: /* cmd ::= REINDEX */
+{yygotominor.yy399 = new SqliteReindex();}
+ break;
+ case 389: /* cmd ::= REINDEX nm dbnm */
+ case 390: /* cmd ::= REINDEX ID_COLLATE */ yytestcase(yyruleno==390);
+{
+ yygotominor.yy399 = new SqliteReindex(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-1].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 393: /* cmd ::= ANALYZE */
+{
+ yygotominor.yy399 = new SqliteAnalyze();
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 394: /* cmd ::= ANALYZE nm dbnm */
+{
+ yygotominor.yy399 = new SqliteAnalyze(*(yymsp[-1].minor.yy211), *(yymsp[0].minor.yy211));
+ delete yymsp[-1].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 397: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+{
+ yygotominor.yy399 = new SqliteAlterTable(
+ yymsp[-3].minor.yy66->name1,
+ yymsp[-3].minor.yy66->name2,
+ *(yymsp[0].minor.yy211)
+ );
+ delete yymsp[0].minor.yy211;
+ delete yymsp[-3].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 398: /* cmd ::= ALTER TABLE fullname ADD kwcolumn_opt column */
+{
+ yygotominor.yy399 = new SqliteAlterTable(
+ yymsp[-3].minor.yy66->name1,
+ yymsp[-3].minor.yy66->name2,
+ *(yymsp[-1].minor.yy237),
+ yymsp[0].minor.yy425
+ );
+ delete yymsp[-1].minor.yy237;
+ delete yymsp[-3].minor.yy66;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 399: /* cmd ::= ALTER TABLE fullname RENAME TO ID_TAB_NEW */
+{ yy_destructor(yypParser,181,&yymsp[-3].minor);
+}
+ break;
+ case 405: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+{
+ yygotominor.yy399 = new SqliteCreateVirtualTable(
+ *(yymsp[-4].minor.yy237),
+ *(yymsp[-3].minor.yy211),
+ *(yymsp[-2].minor.yy211),
+ *(yymsp[0].minor.yy211)
+ );
+ delete yymsp[-4].minor.yy237;
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-2].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 406: /* create_vtab ::= CREATE VIRTUAL TABLE ifnotexists nm dbnm USING nm LP vtabarglist RP */
+{
+ yygotominor.yy399 = new SqliteCreateVirtualTable(
+ *(yymsp[-7].minor.yy237),
+ *(yymsp[-6].minor.yy211),
+ *(yymsp[-5].minor.yy211),
+ *(yymsp[-3].minor.yy211),
+ *(yymsp[-1].minor.yy445)
+ );
+ delete yymsp[-6].minor.yy211;
+ delete yymsp[-5].minor.yy211;
+ delete yymsp[-3].minor.yy211;
+ delete yymsp[-7].minor.yy237;
+ delete yymsp[-1].minor.yy445;
+ objectForTokens = yygotominor.yy399;
+ }
+ break;
+ case 409: /* vtabarglist ::= vtabarg */
+{
+ yygotominor.yy445 = new ParserStringList();
+ yygotominor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 410: /* vtabarglist ::= vtabarglist COMMA vtabarg */
+{
+ yymsp[-2].minor.yy445->append((yymsp[0].minor.yy211)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg
+ yygotominor.yy445 = yymsp[-2].minor.yy445;
+ delete yymsp[0].minor.yy211;
+ DONT_INHERIT_TOKENS("vtabarglist");
+ }
+ break;
+ case 412: /* vtabarg ::= vtabarg vtabargtoken */
+{
+ yymsp[-1].minor.yy211->append(" "+ *(yymsp[0].minor.yy211));
+ yygotominor.yy211 = yymsp[-1].minor.yy211;
+ delete yymsp[0].minor.yy211;
+ }
+ break;
+ case 413: /* vtabargtoken ::= ANY */
+{
+ yygotominor.yy211 = new QString(yymsp[0].minor.yy0->value);
+ }
+ break;
+ case 414: /* vtabargtoken ::= LP anylist RP */
+{
+ yygotominor.yy211 = new QString("(");
+ yygotominor.yy211->append(*(yymsp[-1].minor.yy211));
+ yygotominor.yy211->append(")");
+ delete yymsp[-1].minor.yy211;
+ }
+ break;
+ case 416: /* anylist ::= anylist LP anylist RP */
+{
+ yygotominor.yy211 = yymsp[-3].minor.yy211;
+ yygotominor.yy211->append("(");
+ yygotominor.yy211->append(*(yymsp[-1].minor.yy211));
+ yygotominor.yy211->append(")");
+ delete yymsp[-1].minor.yy211;
+ DONT_INHERIT_TOKENS("anylist");
+ }
+ break;
+ case 417: /* anylist ::= anylist ANY */
+{
+ yygotominor.yy211 = yymsp[-1].minor.yy211;
+ yygotominor.yy211->append(yymsp[0].minor.yy0->value);
+ DONT_INHERIT_TOKENS("anylist");
+ }
+ break;
+ case 418: /* with ::= */
+{yygotominor.yy367 = nullptr;}
+ break;
+ case 419: /* with ::= WITH wqlist */
+{
+ yygotominor.yy367 = yymsp[0].minor.yy367;
+ objectForTokens = yygotominor.yy367;
+ }
+ break;
+ case 420: /* with ::= WITH RECURSIVE wqlist */
+{
+ yygotominor.yy367 = yymsp[0].minor.yy367;
+ yygotominor.yy367->recursive = true;
+ objectForTokens = yygotominor.yy367;
+ }
+ break;
+ case 421: /* wqlist ::= nm idxlist_opt AS LP select RP */
+{
+ yygotominor.yy367 = SqliteWith::append(*(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123);
+ delete yymsp[-5].minor.yy211;
+ delete yymsp[-4].minor.yy139;
+ }
+ break;
+ case 422: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */
+{
+ yygotominor.yy367 = SqliteWith::append(yymsp[-7].minor.yy367, *(yymsp[-5].minor.yy211), *(yymsp[-4].minor.yy139), yymsp[-1].minor.yy123);
+ delete yymsp[-5].minor.yy211;
+ delete yymsp[-4].minor.yy139;
+ DONT_INHERIT_TOKENS("wqlist");
+ }
+ break;
+ case 423: /* wqlist ::= ID_TAB_NEW */
+{
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ yygotominor.yy367 = new SqliteWith();
+ }
+ break;
+ default:
+ /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
+ break;
+ };
+ }
+ assert( yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0])) );
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+
+ // Store tokens for the rule in parser context
+ QList<Token*> allTokens;
+ QList<Token*> allTokensWithAllInherited;
+ QString keyForTokensMap;
+ int tokensMapKeyCnt;
+ if (parserContext->setupTokens)
+ {
+ if (objectForTokens)
+ {
+ // In case this is a list with recurrent references we need
+ // to clear tokens before adding the new and extended list.
+ objectForTokens->tokens.clear();
+ }
+
+ QList<Token*> tokens;
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ tokens.clear();
+ const char* fieldName = yyTokenName[yypParser->yystack[i].major];
+ if (parserContext->isManagedToken(yypParser->yystack[i].minor.yy0))
+ tokens += yypParser->yystack[i].minor.yy0;
+
+ tokens += *(yypParser->yystack[i].tokens);
+
+ if (!noTokenInheritanceFields.contains(fieldName))
+ {
+ if (objectForTokens)
+ {
+ keyForTokensMap = fieldName;
+ tokensMapKeyCnt = 2;
+ while (objectForTokens->tokensMap.contains(keyForTokensMap))
+ keyForTokensMap = fieldName + QString::number(tokensMapKeyCnt++);
+
+ objectForTokens->tokensMap[keyForTokensMap] = parserContext->getTokenPtrList(tokens);
+ }
+
+ allTokens += tokens;
+ }
+ else
+ {
+ // If field is mentioned only once, then only one occurance of it will be ignored.
+ // Second one should be inherited. See "anylist" definition for explanation why.
+ noTokenInheritanceFields.removeOne(fieldName);
+ }
+ allTokensWithAllInherited += tokens;
+ }
+ if (objectForTokens)
+ {
+ objectForTokens->tokens += parserContext->getTokenPtrList(allTokens);
+ }
+ }
+
+ // Clear token lists
+ for (int i = yypParser->yyidx - yysize + 1; i <= yypParser->yyidx; i++)
+ {
+ delete yypParser->yystack[i].tokens;
+ yypParser->yystack[i].tokens = nullptr;
+ }
+
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+ if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+ /* If we are not debugging and the reduce action popped at least
+ ** one element off the stack, then we can push the new element back
+ ** onto the stack here, and skip the stack overflow test in yy_shift().
+ ** That gives a significant speed improvement. */
+ if( yysize ){
+ yypParser->yyidx++;
+ yymsp -= yysize-1;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yymsp->minor = yygotominor;
+ if (parserContext->setupTokens)
+ *(yypParser->yystack[yypParser->yyidx].tokens) = allTokens;
+ }else
+#endif
+ {
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ if (parserContext->setupTokens)
+ {
+ QList<Token*>* tokensPtr = yypParser->yystack[yypParser->yyidx].tokens;
+ *tokensPtr = allTokensWithAllInherited + *tokensPtr;
+ }
+ }
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ sqlite3_parseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+ sqlite3_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ sqlite3_parseARG_FETCH;
+#define TOKEN (yyminor.yy0)
+
+ UNUSED_PARAMETER(yymajor);
+ parserContext->error(TOKEN, QObject::tr("Syntax error"));
+ //qDebug() << "near " << TOKEN->toString() << ": syntax error";
+ sqlite3_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ sqlite3_parseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+ sqlite3_parseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "sqlite3_parseAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void sqlite3_parse(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ sqlite3_parseTOKENTYPE yyminor /* The value for the token */
+ sqlite3_parseARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ int yyendofinput; /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
+ yyminorunion = yyzerominor;
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ yypParser->yystack[0].tokens = new QList<Token*>();
+ }
+ yyminorunion.yy0 = yyminor;
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ yyendofinput = (yymajor==0);
+#endif
+ sqlite3_parseARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s [%s] (lemon type: %s)\n",
+ yyTracePrompt,
+ yyminor->value.toLatin1().data(),
+ yyminor->typeString().toLatin1().data(),
+ yyTokenName[yymajor]); }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ yymajor = YYNOCODE;
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
+ int yymx;
+#endif
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_reduce_action(
+ yypParser->yystack[yypParser->yyidx].stateno,
+ YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+ /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+ ** do any kind of error recovery. Instead, simply invoke the syntax
+ ** error routine and continue going as if nothing had happened.
+ **
+ ** Applications can set this macro (for example inside %include) if
+ ** they intend to abandon the parse upon the first syntax error seen.
+ */
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 1; // not 3 valid tokens, but 1
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h
new file mode 100644
index 0000000..d18c81c
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.h
@@ -0,0 +1,167 @@
+#define TK3_ILLEGAL 1
+#define TK3_COMMENT 2
+#define TK3_SPACE 3
+#define TK3_ID 4
+#define TK3_ABORT 5
+#define TK3_ACTION 6
+#define TK3_AFTER 7
+#define TK3_ANALYZE 8
+#define TK3_ASC 9
+#define TK3_ATTACH 10
+#define TK3_BEFORE 11
+#define TK3_BEGIN 12
+#define TK3_BY 13
+#define TK3_CASCADE 14
+#define TK3_CAST 15
+#define TK3_COLUMNKW 16
+#define TK3_CONFLICT 17
+#define TK3_DATABASE 18
+#define TK3_DEFERRED 19
+#define TK3_DESC 20
+#define TK3_DETACH 21
+#define TK3_EACH 22
+#define TK3_END 23
+#define TK3_EXCLUSIVE 24
+#define TK3_EXPLAIN 25
+#define TK3_FAIL 26
+#define TK3_FOR 27
+#define TK3_IGNORE 28
+#define TK3_IMMEDIATE 29
+#define TK3_INDEXED 30
+#define TK3_INITIALLY 31
+#define TK3_INSTEAD 32
+#define TK3_LIKE_KW 33
+#define TK3_MATCH 34
+#define TK3_NO 35
+#define TK3_PLAN 36
+#define TK3_QUERY 37
+#define TK3_KEY 38
+#define TK3_OF 39
+#define TK3_OFFSET 40
+#define TK3_PRAGMA 41
+#define TK3_RAISE 42
+#define TK3_RECURSIVE 43
+#define TK3_RELEASE 44
+#define TK3_REPLACE 45
+#define TK3_RESTRICT 46
+#define TK3_ROW 47
+#define TK3_ROLLBACK 48
+#define TK3_SAVEPOINT 49
+#define TK3_TEMP 50
+#define TK3_TRIGGER 51
+#define TK3_VACUUM 52
+#define TK3_VIEW 53
+#define TK3_VIRTUAL 54
+#define TK3_WITH 55
+#define TK3_WITHOUT 56
+#define TK3_REINDEX 57
+#define TK3_RENAME 58
+#define TK3_CTIME_KW 59
+#define TK3_IF 60
+#define TK3_ANY 61
+#define TK3_OR 62
+#define TK3_AND 63
+#define TK3_NOT 64
+#define TK3_IS 65
+#define TK3_BETWEEN 66
+#define TK3_IN 67
+#define TK3_ISNULL 68
+#define TK3_NOTNULL 69
+#define TK3_NE 70
+#define TK3_EQ 71
+#define TK3_GT 72
+#define TK3_LE 73
+#define TK3_LT 74
+#define TK3_GE 75
+#define TK3_ESCAPE 76
+#define TK3_BITAND 77
+#define TK3_BITOR 78
+#define TK3_LSHIFT 79
+#define TK3_RSHIFT 80
+#define TK3_PLUS 81
+#define TK3_MINUS 82
+#define TK3_STAR 83
+#define TK3_SLASH 84
+#define TK3_REM 85
+#define TK3_CONCAT 86
+#define TK3_COLLATE 87
+#define TK3_BITNOT 88
+#define TK3_SEMI 89
+#define TK3_TRANSACTION 90
+#define TK3_ID_TRANS 91
+#define TK3_COMMIT 92
+#define TK3_TO 93
+#define TK3_CREATE 94
+#define TK3_TABLE 95
+#define TK3_LP 96
+#define TK3_RP 97
+#define TK3_AS 98
+#define TK3_DOT 99
+#define TK3_ID_TAB_NEW 100
+#define TK3_ID_DB 101
+#define TK3_CTX_ROWID_KW 102
+#define TK3_EXISTS 103
+#define TK3_COMMA 104
+#define TK3_ID_COL_NEW 105
+#define TK3_STRING 106
+#define TK3_JOIN_KW 107
+#define TK3_ID_COL_TYPE 108
+#define TK3_CONSTRAINT 109
+#define TK3_DEFAULT 110
+#define TK3_NULL 111
+#define TK3_PRIMARY 112
+#define TK3_UNIQUE 113
+#define TK3_CHECK 114
+#define TK3_REFERENCES 115
+#define TK3_ID_CONSTR 116
+#define TK3_ID_COLLATE 117
+#define TK3_ID_TAB 118
+#define TK3_INTEGER 119
+#define TK3_FLOAT 120
+#define TK3_BLOB 121
+#define TK3_AUTOINCR 122
+#define TK3_ON 123
+#define TK3_INSERT 124
+#define TK3_DELETE 125
+#define TK3_UPDATE 126
+#define TK3_ID_FK_MATCH 127
+#define TK3_SET 128
+#define TK3_DEFERRABLE 129
+#define TK3_FOREIGN 130
+#define TK3_DROP 131
+#define TK3_ID_VIEW_NEW 132
+#define TK3_ID_VIEW 133
+#define TK3_UNION 134
+#define TK3_ALL 135
+#define TK3_EXCEPT 136
+#define TK3_INTERSECT 137
+#define TK3_SELECT 138
+#define TK3_VALUES 139
+#define TK3_DISTINCT 140
+#define TK3_ID_ALIAS 141
+#define TK3_FROM 142
+#define TK3_USING 143
+#define TK3_JOIN 144
+#define TK3_ID_JOIN_OPTS 145
+#define TK3_ID_IDX 146
+#define TK3_ORDER 147
+#define TK3_GROUP 148
+#define TK3_HAVING 149
+#define TK3_LIMIT 150
+#define TK3_WHERE 151
+#define TK3_ID_COL 152
+#define TK3_INTO 153
+#define TK3_VARIABLE 154
+#define TK3_CASE 155
+#define TK3_ID_FN 156
+#define TK3_ID_ERR_MSG 157
+#define TK3_WHEN 158
+#define TK3_THEN 159
+#define TK3_ELSE 160
+#define TK3_INDEX 161
+#define TK3_ID_IDX_NEW 162
+#define TK3_ID_PRAGMA 163
+#define TK3_ID_TRIG_NEW 164
+#define TK3_ID_TRIG 165
+#define TK3_ALTER 166
+#define TK3_ADD 167
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y
new file mode 100644
index 0000000..31a66a2
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/sqlite3_parse.y
@@ -0,0 +1,2406 @@
+%token_prefix TK3_
+%token_type {Token*}
+%default_type {Token*}
+%extra_argument {ParserContext* parserContext}
+%name sqlite3_parse
+%start_symbol input
+
+%syntax_error {
+ UNUSED_PARAMETER(yymajor);
+ parserContext->error(TOKEN, QObject::tr("Syntax error"));
+ //qDebug() << "near " << TOKEN->toString() << ": syntax error";
+}
+
+%stack_overflow {
+ UNUSED_PARAMETER(yypMinor);
+ parserContext->error(QObject::tr("Parser stack overflow"));
+}
+
+%include {
+#include "token.h"
+#include "parsercontext.h"
+#include "parser_helper_stubs.h"
+#include "common/utils_sql.h"
+#include "parser/ast/sqlitealtertable.h"
+#include "parser/ast/sqliteanalyze.h"
+#include "parser/ast/sqliteattach.h"
+#include "parser/ast/sqlitebegintrans.h"
+#include "parser/ast/sqlitecommittrans.h"
+#include "parser/ast/sqlitecopy.h"
+#include "parser/ast/sqlitecreateindex.h"
+#include "parser/ast/sqlitecreatetable.h"
+#include "parser/ast/sqlitecreatetrigger.h"
+#include "parser/ast/sqlitecreateview.h"
+#include "parser/ast/sqlitecreatevirtualtable.h"
+#include "parser/ast/sqlitedelete.h"
+#include "parser/ast/sqlitedetach.h"
+#include "parser/ast/sqlitedropindex.h"
+#include "parser/ast/sqlitedroptable.h"
+#include "parser/ast/sqlitedroptrigger.h"
+#include "parser/ast/sqlitedropview.h"
+#include "parser/ast/sqliteemptyquery.h"
+#include "parser/ast/sqliteinsert.h"
+#include "parser/ast/sqlitepragma.h"
+#include "parser/ast/sqlitereindex.h"
+#include "parser/ast/sqliterelease.h"
+#include "parser/ast/sqliterollback.h"
+#include "parser/ast/sqlitesavepoint.h"
+#include "parser/ast/sqliteselect.h"
+#include "parser/ast/sqliteupdate.h"
+#include "parser/ast/sqlitevacuum.h"
+#include "parser/ast/sqliteexpr.h"
+#include "parser/ast/sqlitecolumntype.h"
+#include "parser/ast/sqliteconflictalgo.h"
+#include "parser/ast/sqlitesortorder.h"
+#include "parser/ast/sqliteindexedcolumn.h"
+#include "parser/ast/sqliteforeignkey.h"
+#include "parser/ast/sqlitewith.h"
+#include <QObject>
+#include <QDebug>
+
+#define assert(X) Q_ASSERT(X)
+#define UNUSED_PARAMETER(X) (void)(X)
+#define DONT_INHERIT_TOKENS(X) noTokenInheritanceFields << X
+}
+
+// These are extra tokens used by the lexer but never seen by the
+// parser. We put them in a rule so that the parser generator will
+// add them to the parse.h output file.
+
+%nonassoc ILLEGAL COMMENT SPACE.
+
+// The following directive causes tokens ABORT, AFTER, ASC, etc. to
+// fallback to ID if they will not parse as their original value.
+// This obviates the need for the "id" nonterminal.
+// Those keywords: EXCEPT INTERSECT UNION
+// are allowed for fallback if compound selects are disabled,
+// which is not this case.
+%fallback ID
+ ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
+ CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
+ IGNORE IMMEDIATE INDEXED INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
+ QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROLLBACK
+ SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
+ REINDEX RENAME CTIME_KW IF
+ .
+%wildcard ANY.
+
+// Define operator precedence early so that this is the first occurance
+// of the operator tokens in the grammer. Keeping the operators together
+// causes them to be assigned integer values that are close together,
+// which keeps parser tables smaller.
+//
+// The token values assigned to these symbols is determined by the order
+// in which lemon first sees them. It must be the case that ISNULL/NOTNULL,
+// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See
+// the sqlite3ExprIfFalse() routine for additional information on this
+// constraint.
+%left OR.
+%left AND.
+%right NOT.
+%left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
+%left GT LE LT GE.
+%right ESCAPE.
+%left BITAND BITOR LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left STAR SLASH REM.
+%left CONCAT.
+%left COLLATE.
+%right BITNOT.
+
+// Input is a single SQL command
+%type cmd {SqliteQuery*}
+%destructor cmd {delete $$;}
+
+input ::= cmdlist.
+
+cmdlist ::= cmdlist ecmd(C). {parserContext->addQuery(C); DONT_INHERIT_TOKENS("cmdlist");}
+cmdlist ::= ecmd(C). {parserContext->addQuery(C);}
+
+%type ecmd {SqliteQuery*}
+%destructor ecmd {delete $$;}
+ecmd(X) ::= SEMI. {X = new SqliteEmptyQuery();}
+ecmd(X) ::= explain(E) cmdx(C) SEMI. {
+ X = C;
+ X->explain = E->explain;
+ X->queryPlan = E->queryPlan;
+ delete E;
+ objectForTokens = X;
+ }
+
+%type explain {ParserStubExplain*}
+%destructor explain {delete $$;}
+explain(X) ::= . {X = new ParserStubExplain(false, false);}
+explain(X) ::= EXPLAIN. {X = new ParserStubExplain(true, false);}
+explain(X) ::= EXPLAIN QUERY PLAN. {X = new ParserStubExplain(true, true);}
+
+%type cmdx {SqliteQuery*}
+%destructor cmdx {delete $$;}
+cmdx(X) ::= cmd(C). {X = C;}
+
+///////////////////// Begin and end transaction. ////////////////////////////
+
+cmd(X) ::= BEGIN transtype(TT)
+ trans_opt(TO). {
+ X = new SqliteBeginTrans(
+ TT->type,
+ TO->transactionKw,
+ TO->name
+ );
+ delete TO;
+ delete TT;
+ objectForTokens = X;
+ }
+
+%type trans_opt {ParserStubTransDetails*}
+%destructor trans_opt {delete $$;}
+trans_opt(X) ::= . {X = new ParserStubTransDetails();}
+trans_opt(X) ::= TRANSACTION. {
+ X = new ParserStubTransDetails();
+ X->transactionKw = true;
+ }
+trans_opt(X) ::= TRANSACTION nm(N). {
+ X = new ParserStubTransDetails();
+ X->transactionKw = true;
+ X->name = *(N);
+ delete N;
+ }
+trans_opt ::= TRANSACTION ID_TRANS. {}
+
+%type transtype {ParserStubTransDetails*}
+%destructor transtype {delete $$;}
+transtype(X) ::= . {X = new ParserStubTransDetails();}
+transtype(X) ::= DEFERRED. {
+ X = new ParserStubTransDetails();
+ X->type = SqliteBeginTrans::Type::DEFERRED;
+ }
+transtype(X) ::= IMMEDIATE. {
+ X = new ParserStubTransDetails();
+ X->type = SqliteBeginTrans::Type::IMMEDIATE;
+ }
+transtype(X) ::= EXCLUSIVE. {
+ X = new ParserStubTransDetails();
+ X->type = SqliteBeginTrans::Type::EXCLUSIVE;
+ }
+cmd(X) ::= COMMIT trans_opt(T). {
+ X = new SqliteCommitTrans(
+ T->transactionKw,
+ T->name,
+ false
+ );
+ delete T;
+ objectForTokens = X;
+ }
+cmd(X) ::= END trans_opt(T). {
+ X = new SqliteCommitTrans(
+ T->transactionKw,
+ T->name,
+ true
+ );
+ delete T;
+ objectForTokens = X;
+ }
+cmd(X) ::= ROLLBACK trans_opt(T). {
+ X = new SqliteRollback(
+ T->transactionKw,
+ T->name
+ );
+ delete T;
+ objectForTokens = X;
+ }
+
+%type savepoint_opt {bool*}
+%destructor savepoint_opt {delete $$;}
+savepoint_opt(X) ::= SAVEPOINT. {X = new bool(true);}
+savepoint_opt(X) ::= . {X = new bool(false);}
+
+cmd(X) ::= SAVEPOINT nm(N). {
+ X = new SqliteSavepoint(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+cmd(X) ::= RELEASE savepoint_opt(S) nm(N). {
+ X = new SqliteRelease(*(S), *(N));
+ delete N;
+ objectForTokens = X;
+ }
+cmd(X) ::= ROLLBACK trans_opt(T) TO
+ savepoint_opt(S) nm(N). {
+ X = new SqliteRollback(
+ T->transactionKw,
+ *(S),
+ *(N)
+ );
+ delete S;
+ delete T;
+ objectForTokens = X;
+ }
+cmd ::= SAVEPOINT ID_TRANS. {}
+cmd ::= RELEASE savepoint_opt ID_TRANS. {}
+cmd ::= ROLLBACK trans_opt TO savepoint_opt
+ ID_TRANS. {}
+
+///////////////////// The CREATE TABLE statement ////////////////////////////
+
+cmd(X) ::= CREATE temp(T) TABLE
+ ifnotexists(E) fullname(N)
+ LP columnlist(CL)
+ conslist_opt(CS) RP
+ table_options(F). {
+ X = new SqliteCreateTable(
+ *(T),
+ *(E),
+ N->name1,
+ N->name2,
+ *(CL),
+ *(CS),
+ *(F)
+ );
+ delete E;
+ delete T;
+ delete CL;
+ delete CS;
+ delete N;
+ delete F;
+ objectForTokens = X;
+ }
+cmd(X) ::= CREATE temp(T) TABLE
+ ifnotexists(E) fullname(N)
+ AS select(S). {
+ X = new SqliteCreateTable(
+ *(T),
+ *(E),
+ N->name1,
+ N->name2,
+ S
+ );
+ delete E;
+ delete T;
+ delete N;
+ objectForTokens = X;
+ }
+cmd ::= CREATE temp TABLE ifnotexists
+ nm DOT ID_TAB_NEW. {}
+cmd ::= CREATE temp TABLE ifnotexists
+ ID_DB|ID_TAB_NEW. {}
+
+%type table_options {QString*}
+%destructor table_options {delete $$;}
+table_options(X) ::= . {X = new QString();}
+table_options(X) ::= WITHOUT nm(N). {
+ if (N->toLower() != "rowid")
+ parserContext->errorAtToken(QString("Invalid table option: %1").arg(*(N)));
+
+ X = N;
+ }
+table_options ::= WITHOUT CTX_ROWID_KW. {}
+
+%type ifnotexists {bool*}
+%destructor ifnotexists {delete $$;}
+ifnotexists(X) ::= . {X = new bool(false);}
+ifnotexists(X) ::= IF NOT EXISTS. {X = new bool(true);}
+
+%type temp {int*}
+%destructor temp {delete $$;}
+temp(X) ::= TEMP(T). {X = new int( (T->value.length() > 4) ? 2 : 1 );}
+temp(X) ::= . {X = new int(0);}
+
+%type columnlist {ParserCreateTableColumnList*}
+%destructor columnlist {delete $$;}
+columnlist(X) ::= columnlist(L)
+ COMMA column(C). {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("columnlist");
+ }
+columnlist(X) ::= column(C). {
+ X = new ParserCreateTableColumnList();
+ X->append(C);
+ }
+
+// A "column" is a complete description of a single column in a
+// CREATE TABLE statement. This includes the column name, its
+// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
+// NOT NULL and so forth.
+
+%type column {SqliteCreateTable::Column*}
+%destructor column {delete $$;}
+column(X) ::= columnid(C) type(T)
+ carglist(L). {
+ X = new SqliteCreateTable::Column(*(C), T, *(L));
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+
+%type columnid {QString*}
+%destructor columnid {delete $$;}
+columnid(X) ::= nm(N). {X = N;}
+columnid ::= ID_COL_NEW. {}
+
+
+// An IDENTIFIER can be a generic identifier, or one of several
+// keywords. Any non-standard keyword can also be an identifier.
+%type id {QString*}
+%destructor id {delete $$;}
+id(X) ::= ID(T). {
+ X = new QString(
+ stripObjName(
+ T->value,
+ parserContext->dialect
+ )
+ );
+ }
+
+// Why would INDEXED be defined individually like this? I don't know.
+// It was like this in the original SQLite grammar, but it doesn't
+// make any sense, since we have a fallback mechanism for such things.
+// Anyway, this makes "INDEXED" appear in weird places of completion
+// suggestions, so I remove it for now. Will see how it works.
+// id(X) ::= INDEXED(T). {X = new QString(T->value);}
+
+// And "ids" is an identifer-or-string.
+%type ids {QString*}
+%destructor ids {delete $$;}
+ids(X) ::= ID|STRING(T). {X = new QString(T->value);}
+
+// The name of a column or table can be any of the following:
+%type nm {QString*}
+%destructor nm {delete $$;}
+nm(X) ::= id(N). {X = N;}
+nm(X) ::= STRING(N). {X = new QString(stripString(N->value));}
+nm(X) ::= JOIN_KW(N). {X = new QString(N->value);}
+
+// A typetoken is really one or more tokens that form a type name such
+// as can be found after the column name in a CREATE TABLE statement.
+// Multiple tokens are concatenated to form the value of the typetoken.
+%type type {SqliteColumnType*}
+%destructor type {delete $$;}
+type(X) ::= . {X = nullptr;}
+type(X) ::= typetoken(T). {X = T;}
+
+%type typetoken {SqliteColumnType*}
+%destructor typetoken {delete $$;}
+typetoken(X) ::= typename(N). {
+ X = new SqliteColumnType(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+typetoken(X) ::= typename(N)
+ LP signed(P) RP. {
+ X = new SqliteColumnType(*(N), *(P));
+ delete N;
+ delete P;
+ objectForTokens = X;
+ }
+typetoken(X) ::= typename(N) LP signed(P)
+ COMMA signed(S) RP. {
+ X = new SqliteColumnType(*(N), *(P), *(S));
+ delete N;
+ delete P;
+ delete S;
+ objectForTokens = X;
+ }
+
+%type typename {QString*}
+%destructor typename {delete $$;}
+typename(X) ::= ids(I). {X = I;}
+typename(X) ::= typename(T) ids(I). {
+ T->append(" " + *(I));
+ delete I;
+ X = T;
+ }
+typename ::= ID_COL_TYPE. {}
+
+%type signed {QVariant*}
+%destructor signed {delete $$;}
+signed(X) ::= plus_num(N). {X = N;}
+signed(X) ::= minus_num(N). {X = N;}
+
+// "carglist" is a list of additional constraints that come after the
+// column name and column type in a CREATE TABLE statement.
+%type carglist {ParserCreateTableColumnConstraintList*}
+%destructor carglist {delete $$;}
+carglist(X) ::= carglist(L) ccons(C). {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("carglist");
+ }
+carglist(X) ::= . {X = new ParserCreateTableColumnConstraintList();}
+
+%type ccons {SqliteCreateTable::Column::Constraint*}
+%destructor ccons {delete $$;}
+ccons(X) ::= CONSTRAINT nm(N). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefNameOnly(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT term(T). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefTerm(*(T));
+ delete T;
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT LP expr(E) RP. {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefExpr(E);
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT PLUS term(T). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefTerm(*(T), false);
+ delete T;
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT MINUS term(T). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefTerm(*(T), true);
+ delete T;
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT id(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefId(*(I));
+ delete I;
+ objectForTokens = X;
+ }
+ccons(X) ::= DEFAULT CTIME_KW(K). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefCTime(K->value);
+ objectForTokens = X;
+ }
+
+// In addition to the type name, we also care about the primary key and
+// UNIQUE constraints.
+ccons(X) ::= NULL onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initNull(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= NOT NULL onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initNotNull(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= PRIMARY KEY sortorder(O)
+ onconf(C) autoinc(A). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initPk(*(O), *(C), *(A));
+ delete O;
+ delete A;
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= UNIQUE onconf(C). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initUnique(*(C));
+ delete C;
+ objectForTokens = X;
+ }
+ccons(X) ::= CHECK LP expr(E) RP. {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initCheck(E);
+ objectForTokens = X;
+ }
+ccons(X) ::= REFERENCES nm(N)
+ idxlist_opt(I) refargs(A). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initFk(*(N), *(I), *(A));
+ delete N;
+ delete A;
+ delete I;
+ objectForTokens = X;
+ }
+ccons(X) ::= defer_subclause(D). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initDefer(D->initially, D->deferrable);
+ delete D;
+ objectForTokens = X;
+ }
+ccons(X) ::= COLLATE ids(I). {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initColl(*(I));
+ delete I;
+ objectForTokens = X;
+ }
+
+ccons ::= CONSTRAINT ID_CONSTR. {}
+ccons ::= COLLATE ID_COLLATE. {}
+ccons ::= REFERENCES ID_TAB. {}
+ccons(X) ::= CHECK LP RP. {
+ X = new SqliteCreateTable::Column::Constraint();
+ X->initCheck();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+%type term {QVariant*}
+%destructor term {delete $$;}
+term(X) ::= NULL. {
+ X = new QVariant();
+ }
+term(X) ::= INTEGER(N). {
+ int base = 10;
+ if (N->value.startsWith("0x", Qt::CaseInsensitive))
+ base = 16;
+
+ X = new QVariant(N->value.toLongLong(nullptr, base));
+ }
+term(X) ::= FLOAT(N). {
+ X = new QVariant(QVariant(N->value).toDouble());
+ }
+term(X) ::= STRING|BLOB(S). {X = new QVariant(S->value);}
+
+// The optional AUTOINCREMENT keyword
+%type autoinc {bool*}
+%destructor autoinc {delete $$;}
+autoinc(X) ::= . {X = new bool(false);}
+autoinc(X) ::= AUTOINCR. {X = new bool(true);}
+
+// The next group of rules parses the arguments to a REFERENCES clause
+// that determine if the referential integrity checking is deferred or
+// or immediate and which determine what action to take if a ref-integ
+// check fails.
+%type refargs {ParserFkConditionList*}
+%destructor refargs {delete $$;}
+refargs(X) ::= . {X = new ParserFkConditionList();}
+refargs(X) ::= refargs(L) refarg(A). {
+ L->append(A);
+ X = L;
+ DONT_INHERIT_TOKENS("refargs");
+ }
+
+%type refarg {SqliteForeignKey::Condition*}
+%destructor refarg {delete $$;}
+refarg(X) ::= MATCH nm(N). {
+ X = new SqliteForeignKey::Condition(*(N));
+ delete N;
+ }
+refarg(X) ::= ON INSERT refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::INSERT, *(R)); delete R;}
+refarg(X) ::= ON DELETE refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::DELETE, *(R)); delete R;}
+refarg(X) ::= ON UPDATE refact(R). {X = new SqliteForeignKey::Condition(SqliteForeignKey::Condition::UPDATE, *(R)); delete R;}
+refarg ::= MATCH ID_FK_MATCH. {}
+
+%type refact {SqliteForeignKey::Condition::Reaction*}
+%destructor refact {delete $$;}
+refact(X) ::= SET NULL. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_NULL);}
+refact(X) ::= SET DEFAULT. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::SET_DEFAULT);}
+refact(X) ::= CASCADE. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::CASCADE);}
+refact(X) ::= RESTRICT. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::RESTRICT);}
+refact(X) ::= NO ACTION. {X = new SqliteForeignKey::Condition::Reaction(SqliteForeignKey::Condition::NO_ACTION);}
+
+%type defer_subclause {ParserDeferSubClause*}
+%destructor defer_subclause {delete $$;}
+defer_subclause(X) ::= NOT DEFERRABLE
+ init_deferred_pred_opt(I). {
+ X = new ParserDeferSubClause(SqliteDeferrable::NOT_DEFERRABLE, *(I));
+ delete I;
+ }
+defer_subclause(X) ::= DEFERRABLE
+ init_deferred_pred_opt(I). {
+ X = new ParserDeferSubClause(SqliteDeferrable::DEFERRABLE, *(I));
+ delete I;
+ }
+
+%type init_deferred_pred_opt {SqliteInitially*}
+%destructor init_deferred_pred_opt {delete $$;}
+init_deferred_pred_opt(X) ::= . {X = new SqliteInitially(SqliteInitially::null);}
+init_deferred_pred_opt(X) ::= INITIALLY
+ DEFERRED. {X = new SqliteInitially(SqliteInitially::DEFERRED);}
+init_deferred_pred_opt(X) ::= INITIALLY
+ IMMEDIATE. {X = new SqliteInitially(SqliteInitially::IMMEDIATE);}
+
+%type conslist_opt {ParserCreateTableConstraintList*}
+%destructor conslist_opt {delete $$;}
+conslist_opt(X) ::= . {X = new ParserCreateTableConstraintList();}
+conslist_opt(X) ::= COMMA conslist(L). {X = L;}
+
+%type conslist {ParserCreateTableConstraintList*}
+%destructor conslist {delete $$;}
+conslist(X) ::= conslist(L) tconscomma(CM)
+ tcons(C). {
+ C->afterComma = *(CM);
+ L->append(C);
+ X = L;
+ delete CM;
+ DONT_INHERIT_TOKENS("conslist");
+ }
+conslist(X) ::= tcons(C). {
+ X = new ParserCreateTableConstraintList();
+ X->append(C);
+ }
+
+%type tconscomma {bool*}
+%destructor tconscomma {delete $$;}
+tconscomma(X) ::= COMMA. {X = new bool(true);}
+tconscomma(X) ::= . {X = new bool(false);}
+
+%type tcons {SqliteCreateTable::Constraint*}
+%destructor tcons {delete $$;}
+tcons(X) ::= CONSTRAINT nm(N). {
+ X = new SqliteCreateTable::Constraint();
+ X->initNameOnly(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+tcons(X) ::= PRIMARY KEY LP idxlist(L)
+ autoinc(I) RP onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initPk(*(L), *(I), *(C));
+ delete I;
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+tcons(X) ::= UNIQUE LP idxlist(L) RP
+ onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initUnique(*(L), *(C));
+ delete C;
+ delete L;
+ objectForTokens = X;
+ }
+tcons(X) ::= CHECK LP expr(E) RP onconf(C). {
+ X = new SqliteCreateTable::Constraint();
+ X->initCheck(E, *(C));
+ objectForTokens = X;
+ }
+tcons(X) ::= FOREIGN KEY LP idxlist(L) RP
+ REFERENCES nm(N) idxlist_opt(IL)
+ refargs(R) defer_subclause_opt(D). {
+ X = new SqliteCreateTable::Constraint();
+ X->initFk(
+ *(L),
+ *(N),
+ *(IL),
+ *(R),
+ D->initially,
+ D->deferrable
+ );
+ delete N;
+ delete R;
+ delete D;
+ delete IL;
+ delete L;
+ objectForTokens = X;
+ }
+
+tcons ::= CONSTRAINT ID_CONSTR. {}
+tcons ::= FOREIGN KEY LP idxlist RP
+ REFERENCES ID_TAB. {}
+tcons(X) ::= CHECK LP RP onconf. {
+ X = new SqliteCreateTable::Constraint();
+ X->initCheck();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+%type defer_subclause_opt {ParserDeferSubClause*}
+%destructor defer_subclause_opt {delete $$;}
+defer_subclause_opt(X) ::= . {X = new ParserDeferSubClause(SqliteDeferrable::null, SqliteInitially::null);}
+defer_subclause_opt(X) ::=
+ defer_subclause(D). {X = D;}
+
+// The following is a non-standard extension that allows us to declare the
+// default behavior when there is a constraint conflict.
+
+%type onconf {SqliteConflictAlgo*}
+%destructor onconf {delete $$;}
+onconf(X) ::= . {X = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+onconf(X) ::= ON CONFLICT resolvetype(R). {X = R;}
+
+%type orconf {SqliteConflictAlgo*}
+%destructor orconf {delete $$;}
+orconf(X) ::= . {X = new SqliteConflictAlgo(SqliteConflictAlgo::null);}
+orconf(X) ::= OR resolvetype(R). {X = R;}
+
+%type resolvetype {SqliteConflictAlgo*}
+%destructor resolvetype {delete $$;}
+resolvetype(X) ::= raisetype(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= IGNORE(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+resolvetype(X) ::= REPLACE(V). {X = new SqliteConflictAlgo(sqliteConflictAlgo(V->value));}
+
+////////////////////////// The DROP TABLE /////////////////////////////////////
+
+cmd(X) ::= DROP TABLE ifexists(E)
+ fullname(N). {
+ X = new SqliteDropTable(*(E), N->name1, N->name2);
+ delete E;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP TABLE ifexists nm DOT
+ ID_TAB. {}
+cmd ::= DROP TABLE ifexists ID_DB|ID_TAB. {}
+
+%type ifexists {bool*}
+%destructor ifexists {delete $$;}
+ifexists(X) ::= IF EXISTS. {X = new bool(true);}
+ifexists(X) ::= . {X = new bool(false);}
+
+///////////////////// The CREATE VIEW statement /////////////////////////////
+
+cmd(X) ::= CREATE temp(T) VIEW
+ ifnotexists(E) fullname(N)
+ AS select(S). {
+ X = new SqliteCreateView(*(T), *(E), N->name1, N->name2, S);
+ delete T;
+ delete E;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= CREATE temp VIEW ifnotexists
+ nm DOT ID_VIEW_NEW. {}
+cmd ::= CREATE temp VIEW ifnotexists
+ ID_DB|ID_VIEW_NEW. {}
+
+cmd(X) ::= DROP VIEW ifexists(E)
+ fullname(N). {
+ X = new SqliteDropView(*(E), N->name1, N->name2);
+ delete E;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP VIEW ifexists nm DOT ID_VIEW. {}
+cmd ::= DROP VIEW ifexists ID_DB|ID_VIEW. {}
+
+//////////////////////// The SELECT statement /////////////////////////////////
+
+cmd(X) ::= select_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type select_stmt {SqliteQuery*}
+%destructor select_stmt {delete $$;}
+select_stmt(X) ::= select(S). {
+ X = S;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+%type select {SqliteSelect*}
+%destructor select {delete $$;}
+select(X) ::= with(W) selectnowith(S). {
+ X = S;
+ S->setWith(W);
+ objectForTokens = X;
+ }
+
+%type selectnowith {SqliteSelect*}
+%destructor selectnowith {delete $$;}
+selectnowith(X) ::= oneselect(S). {
+ X = SqliteSelect::append(S);
+ objectForTokens = X;
+ }
+selectnowith(X) ::= selectnowith(S1)
+ multiselect_op(O)
+ oneselect(S2). {
+ X = SqliteSelect::append(S1, *(O), S2);
+ delete O;
+ objectForTokens = X;
+ }
+selectnowith(X) ::= values(V). {
+ X = SqliteSelect::append(*(V));
+ delete V;
+ objectForTokens = X;
+ }
+selectnowith(X) ::= selectnowith(S1)
+ COMMA
+ values(V). {
+ X = SqliteSelect::append(S1, SqliteSelect::CompoundOperator::UNION_ALL, *(V));
+ delete V;
+ objectForTokens = X;
+ }
+
+%type multiselect_op {SqliteSelect::CompoundOperator*}
+%destructor multiselect_op {delete $$;}
+multiselect_op(X) ::= UNION. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION);}
+multiselect_op(X) ::= UNION ALL. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::UNION_ALL);}
+multiselect_op(X) ::= EXCEPT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::EXCEPT);}
+multiselect_op(X) ::= INTERSECT. {X = new SqliteSelect::CompoundOperator(SqliteSelect::CompoundOperator::INTERSECT);}
+
+%type oneselect {SqliteSelect::Core*}
+%destructor oneselect {delete $$;}
+oneselect(X) ::= SELECT distinct(D)
+ selcollist(L) from(F)
+ where_opt(W) groupby_opt(G)
+ having_opt(H) orderby_opt(O)
+ limit_opt(LI). {
+ X = new SqliteSelect::Core(
+ *(D),
+ *(L),
+ F,
+ W,
+ *(G),
+ H,
+ *(O),
+ LI
+ );
+ delete L;
+ delete D;
+ delete G;
+ delete O;
+ objectForTokens = X;
+ }
+
+%type values {ParserExprNestedList*}
+%destructor values {delete $$;}
+values(X) ::= VALUES LP nexprlist(E) RP. {
+ X = new ParserExprNestedList();
+ X->append(*(E));
+ delete E;
+ }
+values(X) ::= values(L) COMMA LP
+ exprlist(E) RP. {
+ L->append(*(E));
+ X = L;
+ delete E;
+ DONT_INHERIT_TOKENS("values");
+ }
+
+%type distinct {int*}
+%destructor distinct {delete $$;}
+distinct(X) ::= DISTINCT. {X = new int(1);}
+distinct(X) ::= ALL. {X = new int(2);}
+distinct(X) ::= . {X = new int(0);}
+
+%type sclp {ParserResultColumnList*}
+%destructor sclp {delete $$;}
+sclp(X) ::= selcollist(L) COMMA. {X = L;}
+sclp(X) ::= . {X = new ParserResultColumnList();}
+
+%type selcollist {ParserResultColumnList*}
+%destructor selcollist {delete $$;}
+selcollist(X) ::= sclp(L) expr(E) as(N). {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ E,
+ N ? N->asKw : false,
+ N ? N->name : QString::null
+ );
+
+ L->append(obj);
+ X = L;
+ delete N;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L) STAR. {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(true);
+
+ L->append(obj);
+ X = L;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L) nm(N) DOT STAR. {
+ SqliteSelect::Core::ResultColumn* obj =
+ new SqliteSelect::Core::ResultColumn(
+ true,
+ *(N)
+ );
+ L->append(obj);
+ X = L;
+ delete N;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sclp");
+ }
+selcollist(X) ::= sclp(L). {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = L;
+ }
+selcollist ::= sclp ID_TAB DOT STAR. {}
+
+// An option "AS <id>" phrase that can follow one of the expressions that
+// define the result set, or one of the tables in the FROM clause.
+
+%type as {ParserStubAlias*}
+%destructor as {delete $$;}
+as(X) ::= AS nm(N). {
+ X = new ParserStubAlias(*(N), true);
+ delete N;
+ }
+as(X) ::= ids(N). {
+ X = new ParserStubAlias(*(N), false);
+ delete N;
+ }
+as ::= AS ID_ALIAS. {}
+as ::= ID_ALIAS. {}
+as(X) ::= . {X = nullptr;}
+
+// A complete FROM clause.
+
+%type from {SqliteSelect::Core::JoinSource*}
+%destructor from {delete $$;}
+from(X) ::= . {X = nullptr;}
+from(X) ::= FROM joinsrc(L). {X = L;}
+
+%type joinsrc {SqliteSelect::Core::JoinSource*}
+%destructor joinsrc {delete $$;}
+joinsrc(X) ::= singlesrc(S) seltablist(L). {
+ X = new SqliteSelect::Core::JoinSource(
+ S,
+ *(L)
+ );
+ delete L;
+ objectForTokens = X;
+ }
+joinsrc(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::JoinSource();
+ objectForTokens = X;
+ }
+
+%type seltablist {ParserOtherSourceList*}
+%destructor seltablist {delete $$;}
+seltablist(X) ::= seltablist(L) joinop(O)
+ singlesrc(S)
+ joinconstr_opt(C). {
+ SqliteSelect::Core::JoinSourceOther* src =
+ new SqliteSelect::Core::JoinSourceOther(O, S, C);
+
+ L->append(src);
+ X = L;
+ objectForTokens = src;
+ DONT_INHERIT_TOKENS("seltablist");
+ }
+seltablist(X) ::= . {
+ X = new ParserOtherSourceList();
+ }
+
+%type singlesrc {SqliteSelect::Core::SingleSource*}
+%destructor singlesrc {delete $$;}
+singlesrc(X) ::= nm(N1) dbnm(N2) as(A)
+ indexed_opt(I). {
+ X = new SqliteSelect::Core::SingleSource(
+ *(N1),
+ *(N2),
+ A ? A->asKw : false,
+ A ? A->name : QString::null,
+ I ? I->notIndexedKw : false,
+ I ? I->indexedBy : QString::null
+ );
+ delete N1;
+ delete N2;
+ delete A;
+ if (I)
+ delete I;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= LP select(S) RP as(A). {
+ X = new SqliteSelect::Core::SingleSource(
+ S,
+ A ? A->asKw : false,
+ A ? A->name : QString::null
+ );
+ delete A;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= LP joinsrc(J) RP as(A). {
+ X = new SqliteSelect::Core::SingleSource(
+ J,
+ A ? A->asKw : false,
+ A ? A->name : QString::null
+ );
+ delete A;
+ objectForTokens = X;
+ }
+singlesrc(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::SingleSource();
+ objectForTokens = X;
+ }
+singlesrc(X) ::= nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteSelect::Core::SingleSource();
+ X->database = *(N);
+ delete N;
+ objectForTokens = X;
+ }
+
+singlesrc ::= nm DOT ID_TAB. {}
+singlesrc ::= ID_DB|ID_TAB. {}
+singlesrc ::= nm DOT ID_VIEW. {}
+singlesrc ::= ID_DB|ID_VIEW. {}
+
+%type joinconstr_opt {SqliteSelect::Core::JoinConstraint*}
+%destructor joinconstr_opt {delete $$;}
+joinconstr_opt(X) ::= ON expr(E). {
+ X = new SqliteSelect::Core::JoinConstraint(E);
+ objectForTokens = X;
+ }
+joinconstr_opt(X) ::= USING LP
+ inscollist(L) RP. {
+ X = new SqliteSelect::Core::JoinConstraint(*(L));
+ delete L;
+ objectForTokens = X;
+ }
+joinconstr_opt(X) ::= . {X = nullptr;}
+
+%type dbnm {QString*}
+%destructor dbnm {delete $$;}
+dbnm(X) ::= . {X = new QString();}
+dbnm(X) ::= DOT nm(N). {X = N;}
+
+%type fullname {ParserFullName*}
+%destructor fullname {delete $$;}
+fullname(X) ::= nm(N1) dbnm(N2). {
+ X = new ParserFullName();
+ X->name1 = *(N1);
+ X->name2 = *(N2);
+ delete N1;
+ delete N2;
+ }
+
+%type joinop {SqliteSelect::Core::JoinOp*}
+%destructor joinop {delete $$;}
+joinop(X) ::= COMMA. {
+ X = new SqliteSelect::Core::JoinOp(true);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN. {
+ X = new SqliteSelect::Core::JoinOp(false);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value);
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) nm(N) JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value, *(N));
+ delete N;
+ objectForTokens = X;
+ }
+joinop(X) ::= JOIN_KW(K) nm(N1) nm(N2)
+ JOIN. {
+ X = new SqliteSelect::Core::JoinOp(K->value, *(N1), *(N2));
+ delete N1;
+ delete N1;
+ objectForTokens = X;
+ }
+
+joinop ::= ID_JOIN_OPTS. {}
+
+// Note that this block abuses the Token type just a little. If there is
+// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If
+// there is an INDEXED BY clause, then the token is populated as per normal,
+// with z pointing to the token data and n containing the number of bytes
+// in the token.
+//
+// If there is a "NOT INDEXED" clause, then (z==0 && n==1), which is
+// normally illegal. The sqlite3SrcListIndexedBy() function
+// recognizes and interprets this as a special case.
+%type indexed_opt {ParserIndexedBy*}
+%destructor indexed_opt {delete $$;}
+indexed_opt(X) ::= . {X = nullptr;}
+indexed_opt(X) ::= INDEXED BY nm(N). {
+ X = new ParserIndexedBy(*(N));
+ delete N;
+ }
+indexed_opt(X) ::= NOT INDEXED. {X = new ParserIndexedBy(true);}
+
+indexed_opt ::= INDEXED BY ID_IDX. {}
+
+%type orderby_opt {ParserOrderByList*}
+%destructor orderby_opt {delete $$;}
+orderby_opt(X) ::= . {X = new ParserOrderByList();}
+orderby_opt(X) ::= ORDER BY sortlist(L). {X = L;}
+
+// SQLite3 documentation says it's allowed for "COLLATE name" and expr itself handles this.
+%type sortlist {ParserOrderByList*}
+%destructor sortlist {delete $$;}
+sortlist(X) ::= sortlist(L) COMMA expr(E)
+ sortorder(O). {
+ SqliteOrderBy* obj = new SqliteOrderBy(E, *(O));
+ L->append(obj);
+ X = L;
+ delete O;
+ objectForTokens = obj;
+ DONT_INHERIT_TOKENS("sortlist");
+ }
+sortlist(X) ::= expr(E) sortorder(O). {
+ SqliteOrderBy* obj = new SqliteOrderBy(E, *(O));
+ X = new ParserOrderByList();
+ X->append(obj);
+ delete O;
+ objectForTokens = obj;
+ }
+
+%type sortorder {SqliteSortOrder*}
+%destructor sortorder {delete $$;}
+sortorder(X) ::= ASC. {X = new SqliteSortOrder(SqliteSortOrder::ASC);}
+sortorder(X) ::= DESC. {X = new SqliteSortOrder(SqliteSortOrder::DESC);}
+sortorder(X) ::= . {X = new SqliteSortOrder(SqliteSortOrder::null);}
+
+%type groupby_opt {ParserExprList*}
+%destructor groupby_opt {delete $$;}
+groupby_opt(X) ::= . {X = new ParserExprList();}
+groupby_opt(X) ::= GROUP BY nexprlist(L). {X = L;}
+groupby_opt(X) ::= GROUP BY. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserExprList();
+ }
+
+%type having_opt {SqliteExpr*}
+%destructor having_opt {delete $$;}
+having_opt(X) ::= . {X = nullptr;}
+having_opt(X) ::= HAVING expr(E). {X = E;}
+
+%type limit_opt {SqliteLimit*}
+%destructor limit_opt {delete $$;}
+limit_opt(X) ::= . {X = nullptr;}
+limit_opt(X) ::= LIMIT expr(E). {
+ X = new SqliteLimit(E);
+ objectForTokens = X;
+ }
+limit_opt(X) ::= LIMIT expr(E1) OFFSET
+ expr(E2). {
+ X = new SqliteLimit(E1, E2, true);
+ objectForTokens = X;
+ }
+limit_opt(X) ::= LIMIT expr(E1) COMMA
+ expr(E2). {
+ X = new SqliteLimit(E1, E2, false);
+ objectForTokens = X;
+ }
+
+/////////////////////////// The DELETE statement /////////////////////////////
+
+//%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+//cmd ::= DELETE FROM fullname indexed_opt where_opt
+// orderby_opt(O) limit_opt.
+//%endif
+//%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+cmd(X) ::= delete_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type delete_stmt {SqliteQuery*}
+%destructor delete_stmt {delete $$;}
+delete_stmt(X) ::= with(WI) DELETE FROM
+ fullname(N)
+ indexed_opt(I)
+ where_opt(W). {
+ if (I)
+ {
+ if (!I->indexedBy.isNull())
+ {
+ X = new SqliteDelete(
+ N->name1,
+ N->name2,
+ I->indexedBy,
+ W,
+ WI
+ );
+ }
+ else
+ {
+ X = new SqliteDelete(
+ N->name1,
+ N->name2,
+ I->notIndexedKw,
+ W,
+ WI
+ );
+ }
+ delete I;
+ }
+ else
+ {
+ X = new SqliteDelete(
+ N->name1,
+ N->name2,
+ false,
+ W,
+ WI
+ );
+ }
+ delete N;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+//%endif
+
+delete_stmt(X) ::= with(W) DELETE FROM. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->with = W;
+ X = q;
+ objectForTokens = X;
+ }
+delete_stmt(X) ::= with(W) DELETE FROM
+ nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteDelete* q = new SqliteDelete();
+ q->with = W;
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete N;
+ }
+delete_stmt ::= with DELETE FROM
+ nm DOT ID_TAB. {}
+delete_stmt ::= with DELETE FROM
+ ID_DB|ID_TAB. {}
+
+%type where_opt {SqliteExpr*}
+%destructor where_opt {delete $$;}
+where_opt(X) ::= . {X = nullptr;}
+where_opt(X) ::= WHERE expr(E). {X = E;}
+where_opt(X) ::= WHERE. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteExpr();
+ }
+
+////////////////////////// The UPDATE command ////////////////////////////////
+
+//%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+///cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt orderby_opt(O) limit_opt.
+//%endif
+//%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+cmd(X) ::= update_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type update_stmt {SqliteQuery*}
+%destructor update_stmt {delete $$;}
+update_stmt(X) ::= with(WI) UPDATE orconf(C)
+ fullname(N) indexed_opt(I) SET
+ setlist(L) where_opt(W). {
+ X = new SqliteUpdate(
+ *(C),
+ N->name1,
+ N->name2,
+ I ? I->notIndexedKw : false,
+ I ? I->indexedBy : QString::null,
+ *(L),
+ W,
+ WI
+ );
+ delete C;
+ delete N;
+ delete L;
+ if (I)
+ delete I;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+//%endif
+
+update_stmt(X) ::= with(WI) UPDATE
+ orconf(C). {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->with = WI;
+ X = q;
+ objectForTokens = X;
+ delete C;
+ }
+update_stmt(X) ::= with(WI) UPDATE
+ orconf(C) nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteUpdate* q = new SqliteUpdate();
+ q->with = WI;
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete C;
+ delete N;
+ }
+update_stmt ::= with UPDATE orconf nm DOT
+ ID_TAB. {}
+update_stmt ::= with UPDATE orconf
+ ID_DB|ID_TAB. {}
+
+%type setlist {ParserSetValueList*}
+%destructor setlist {delete $$;}
+setlist(X) ::= setlist(L) COMMA nm(N) EQ
+ expr(E). {
+ L->append(ParserSetValue(*(N), E));
+ X = L;
+ delete N;
+ DONT_INHERIT_TOKENS("setlist");
+ }
+setlist(X) ::= nm(N) EQ expr(E). {
+ X = new ParserSetValueList();
+ X->append(ParserSetValue(*(N), E));
+ delete N;
+ }
+setlist(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserSetValueList();
+ }
+setlist(X) ::= setlist(L) COMMA. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = L;
+ }
+
+setlist ::= setlist COMMA ID_COL. {}
+setlist ::= ID_COL. {}
+
+////////////////////////// The INSERT command /////////////////////////////////
+
+cmd(X) ::= insert_stmt(S). {
+ X = S;
+ objectForTokens = X;
+ }
+
+%type insert_stmt {SqliteQuery*}
+%destructor insert_stmt {delete $$;}
+
+insert_stmt(X) ::= with(W) insert_cmd(C)
+ INTO fullname(N)
+ inscollist_opt(I) select(S). {
+ X = new SqliteInsert(
+ C->replace,
+ C->orConflict,
+ N->name1,
+ N->name2,
+ *(I),
+ S,
+ W
+ );
+ delete N;
+ delete C;
+ delete I;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+insert_stmt(X) ::= with(W) insert_cmd(C)
+ INTO fullname(N)
+ inscollist_opt(I) DEFAULT
+ VALUES. {
+ X = new SqliteInsert(
+ C->replace,
+ C->orConflict,
+ N->name1,
+ N->name2,
+ *(I),
+ W
+ );
+ delete N;
+ delete C;
+ delete I;
+ // since it's used in trigger:
+ objectForTokens = X;
+ }
+
+insert_stmt(X) ::= with(W) insert_cmd(C)
+ INTO. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = C->replace;
+ q->onConflict = C->orConflict;
+ q->with = W;
+ X = q;
+ objectForTokens = X;
+ delete C;
+ }
+insert_stmt(X) ::= with(W) insert_cmd(C)
+ INTO nm(N) DOT. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ SqliteInsert* q = new SqliteInsert();
+ q->replaceKw = C->replace;
+ q->onConflict = C->orConflict;
+ q->with = W;
+ q->database = *(N);
+ X = q;
+ objectForTokens = X;
+ delete C;
+ delete N;
+ }
+insert_stmt ::= with insert_cmd INTO
+ ID_DB|ID_TAB. {}
+insert_stmt ::= with insert_cmd INTO
+ nm DOT ID_TAB. {}
+
+%type insert_cmd {ParserStubInsertOrReplace*}
+%destructor insert_cmd {delete $$;}
+insert_cmd(X) ::= INSERT orconf(C). {
+ X = new ParserStubInsertOrReplace(false, *(C));
+ delete C;
+ }
+insert_cmd(X) ::= REPLACE. {X = new ParserStubInsertOrReplace(true);}
+
+%type inscollist_opt {ParserStringList*}
+%destructor inscollist_opt {delete $$;}
+inscollist_opt(X) ::= . {X = new ParserStringList();}
+inscollist_opt(X) ::= LP inscollist(L) RP. {X = L;}
+
+%type inscollist {ParserStringList*}
+%destructor inscollist {delete $$;}
+inscollist(X) ::= inscollist(L) COMMA
+ nm(N). {
+ L->append(*(N));
+ X = L;
+ delete N;
+ DONT_INHERIT_TOKENS("inscollist");
+ }
+inscollist(X) ::= nm(N). {
+ X = new ParserStringList();
+ X->append(*(N));
+ delete N;
+ }
+inscollist(X) ::= . {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new ParserStringList();
+ }
+
+inscollist ::= inscollist COMMA ID_COL. {}
+inscollist ::= ID_COL. {}
+
+/////////////////////////// Expression Processing /////////////////////////////
+
+%type exprx {SqliteExpr*}
+%destructor exprx {delete $$;}
+exprx(X) ::= term(T). {
+ X = new SqliteExpr();
+ X->initLiteral(*(T));
+ delete T;
+ objectForTokens = X;
+ }
+exprx(X) ::= CTIME_KW(K). {
+ X = new SqliteExpr();
+ X->initCTime(K->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= LP expr(E) RP. {
+ X = new SqliteExpr();
+ X->initSubExpr(E);
+ objectForTokens = X;
+ }
+exprx(X) ::= id(N). {
+ X = new SqliteExpr();
+ X->initId(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= JOIN_KW(N). {
+ X = new SqliteExpr();
+ X->initId(N->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT nm(N2). {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2));
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT nm(N2) DOT nm(N3). {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2), *(N3));
+ delete N1;
+ delete N2;
+ delete N3;
+ objectForTokens = X;
+ }
+exprx(X) ::= VARIABLE(V). {
+ X = new SqliteExpr();
+ X->initBindParam(V->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) COLLATE ids(I). {
+ X = new SqliteExpr();
+ X->initCollate(E, *(I));
+ delete I;
+ objectForTokens = X;
+ }
+exprx(X) ::= CAST LP expr(E) AS typetoken(T)
+ RP. {
+ X = new SqliteExpr();
+ X->initCast(E, T);
+ objectForTokens = X;
+ }
+exprx(X) ::= ID(I) LP distinct(D)
+ exprlist(L) RP. {
+ X = new SqliteExpr();
+ X->initFunction(I->value, *(D), *(L));
+ delete D;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= ID(I) LP STAR RP. {
+ X = new SqliteExpr();
+ X->initFunction(I->value, true);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) AND(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) OR(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) LT|GT|GE|LE(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) EQ|NE(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1)
+ BITAND|BITOR|LSHIFT|RSHIFT(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) PLUS|MINUS(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) STAR|SLASH|REM(O)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) CONCAT(O) expr(E2). {
+ X = new SqliteExpr();
+ X->initBinOp(E1, O->value, E2);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) not_opt(N) likeop(L)
+ expr(E2). [LIKE_KW] {
+ X = new SqliteExpr();
+ X->initLike(E1, *(N), *(L), E2);
+ delete N;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) not_opt(N) likeop(L)
+ expr(E2) ESCAPE
+ expr(E3). [LIKE_KW] {
+ X = new SqliteExpr();
+ X->initLike(E1, *(N), *(L), E2, E3);
+ delete N;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) ISNULL|NOTNULL(N). {
+ X = new SqliteExpr();
+ X->initNull(E, N->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) NOT NULL. {
+ X = new SqliteExpr();
+ X->initNull(E, "NOT NULL");
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) IS not_opt(N)
+ expr(E2). {
+ X = new SqliteExpr();
+ X->initIs(E1, *(N), E2);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= NOT(O) expr(E). {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ }
+exprx(X) ::= BITNOT(O) expr(E). {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= MINUS(O) expr(E). [BITNOT] {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= PLUS(O) expr(E). [BITNOT] {
+ X = new SqliteExpr();
+ X->initUnaryOp(E, O->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E1) not_opt(N) BETWEEN
+ expr(E2) AND
+ expr(E3). [BETWEEN] {
+ X = new SqliteExpr();
+ X->initBetween(E1, *(N), E2, E3);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ exprlist(L) RP. [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, *(N), *(L));
+ delete N;
+ delete L;
+ objectForTokens = X;
+ }
+exprx(X) ::= LP select(S) RP. {
+ X = new SqliteExpr();
+ X->initSubSelect(S);
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ select(S) RP. [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, *(N), S);
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= expr(E) not_opt(N) IN nm(N1)
+ dbnm(N2). [IN] {
+ X = new SqliteExpr();
+ X->initIn(E, N, *(N1), *(N2));
+ delete N;
+ delete N1;
+ objectForTokens = X;
+ }
+exprx(X) ::= EXISTS LP select(S) RP. {
+ X = new SqliteExpr();
+ X->initExists(S);
+ objectForTokens = X;
+ }
+exprx(X) ::= CASE case_operand(O)
+ case_exprlist(L)
+ case_else(E) END. {
+ X = new SqliteExpr();
+ X->initCase(O, *(L), E);
+ delete L;
+ objectForTokens = X;
+ }
+
+exprx(X) ::= RAISE LP IGNORE(R) RP. {
+ X = new SqliteExpr();
+ X->initRaise(R->value);
+ objectForTokens = X;
+ }
+exprx(X) ::= RAISE LP raisetype(R) COMMA
+ nm(N) RP. {
+ X = new SqliteExpr();
+ X->initRaise(R->value, *(N));
+ delete N;
+ objectForTokens = X;
+ }
+exprx(X) ::= nm(N1) DOT. {
+ X = new SqliteExpr();
+ X->initId(*(N1), QString::null, QString::null);
+ delete N1;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= nm(N1) DOT nm(N2) DOT. {
+ X = new SqliteExpr();
+ X->initId(*(N1), *(N2), QString::null);
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= expr(E1) not_opt(N) BETWEEN
+ expr(E2). [BETWEEN] {
+ X = new SqliteExpr();
+ delete N;
+ delete E1;
+ delete E2;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= CASE case_operand(O)
+ case_exprlist(L)
+ case_else(E). {
+ X = new SqliteExpr();
+ delete L;
+ delete O;
+ delete E;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+exprx(X) ::= expr(E) not_opt(N) IN LP
+ exprlist(L). [IN] {
+ X = new SqliteExpr();
+ delete N;
+ delete L;
+ delete E;
+ objectForTokens = X;
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ }
+
+exprx ::= expr not_opt IN ID_DB. [IN] {}
+exprx ::= expr not_opt IN nm DOT
+ ID_TAB. [IN] {}
+exprx ::= ID_DB|ID_TAB|ID_COL|ID_FN. {}
+exprx ::= nm DOT ID_TAB|ID_COL. {}
+exprx ::= nm DOT nm DOT ID_COL. {}
+exprx ::= expr COLLATE ID_COLLATE. {}
+exprx ::= RAISE LP raisetype COMMA
+ ID_ERR_MSG RP. {}
+
+%type expr {SqliteExpr*}
+%destructor expr {delete $$;}
+expr(X) ::= exprx(E). {X = E;}
+expr(X) ::= . {
+ X = new SqliteExpr();
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+%type not_opt {bool*}
+%destructor not_opt {delete $$;}
+not_opt(X) ::= . {X = new bool(false);}
+not_opt(X) ::= NOT. {X = new bool(true);}
+
+%type likeop {SqliteExpr::LikeOp*}
+%destructor likeop {delete $$;}
+likeop(X) ::= LIKE_KW|MATCH(T). {X = new SqliteExpr::LikeOp(SqliteExpr::likeOp(T->value));}
+
+%type case_exprlist {ParserExprList*}
+%destructor case_exprlist {delete $$;}
+case_exprlist(X) ::= case_exprlist(L) WHEN
+ expr(E1) THEN expr(E2). {
+ L->append(E1);
+ L->append(E2);
+ X = L;
+ }
+case_exprlist(X) ::= WHEN expr(E1) THEN
+ expr(E2). {
+ X = new ParserExprList();
+ X->append(E1);
+ X->append(E2);
+ }
+
+%type case_else {SqliteExpr*}
+%destructor case_else {delete $$;}
+case_else(X) ::= ELSE expr(E). {X = E;}
+case_else(X) ::= . {X = nullptr;}
+
+%type case_operand {SqliteExpr*}
+%destructor case_operand {delete $$;}
+case_operand(X) ::= exprx(E). {X = E;}
+case_operand(X) ::= . {X = nullptr;}
+
+%type exprlist {ParserExprList*}
+%destructor exprlist {delete $$;}
+exprlist(X) ::= nexprlist(L). {X = L;}
+exprlist(X) ::= . {X = new ParserExprList();}
+
+%type nexprlist {ParserExprList*}
+%destructor nexprlist {delete $$;}
+nexprlist(X) ::= nexprlist(L) COMMA
+ expr(E). {
+ L->append(E);
+ X = L;
+ DONT_INHERIT_TOKENS("nexprlist");
+ }
+nexprlist(X) ::= exprx(E). {
+ X = new ParserExprList();
+ X->append(E);
+ }
+
+///////////////////////////// The CREATE INDEX command ///////////////////////
+
+cmd(X) ::= CREATE uniqueflag(U) INDEX
+ ifnotexists(E) nm(N1) dbnm(N2)
+ ON nm(N3) LP idxlist(L) RP
+ where_opt(W). {
+ X = new SqliteCreateIndex(
+ *(U),
+ *(E),
+ *(N1),
+ *(N2),
+ *(N3),
+ *(L),
+ W
+ );
+ delete E;
+ delete U;
+ delete N1;
+ delete N2;
+ delete N3;
+ delete L;
+ objectForTokens = X;
+ }
+
+cmd ::= CREATE uniqueflag INDEX ifnotexists
+ nm dbnm ON ID_TAB. {}
+cmd ::= CREATE uniqueflag INDEX ifnotexists
+ nm DOT ID_IDX_NEW. {}
+cmd ::= CREATE uniqueflag INDEX ifnotexists
+ ID_DB|ID_IDX_NEW. {}
+
+
+%type uniqueflag {bool*}
+%destructor uniqueflag {delete $$;}
+uniqueflag(X) ::= UNIQUE. {X = new bool(true);}
+uniqueflag(X) ::= . {X = new bool(false);}
+
+%type idxlist_opt {ParserIndexedColumnList*}
+%destructor idxlist_opt {delete $$;}
+idxlist_opt(X) ::= . {X = new ParserIndexedColumnList();}
+idxlist_opt(X) ::= LP idxlist(I) RP. {X = I;}
+
+%type idxlist {ParserIndexedColumnList*}
+%destructor idxlist {delete $$;}
+idxlist(X) ::= idxlist(L) COMMA
+ idxlist_single(S). {
+ L->append(S);
+ X = L;
+ DONT_INHERIT_TOKENS("idxlist");
+ }
+idxlist(X) ::= idxlist_single(S). {
+ X = new ParserIndexedColumnList();
+ X->append(S);
+ }
+
+%type idxlist_single {SqliteIndexedColumn*}
+%destructor idxlist_single {delete $$;}
+idxlist_single(X) ::= nm(N) collate(C)
+ sortorder(S). {
+ SqliteIndexedColumn* obj =
+ new SqliteIndexedColumn(
+ *(N),
+ *(C),
+ *(S)
+ );
+ X = obj;
+ delete S;
+ delete N;
+ delete C;
+ objectForTokens = X;
+ }
+
+idxlist_single ::= ID_COL. {}
+
+%type collate {QString*}
+%destructor collate {delete $$;}
+collate(X) ::= . {X = new QString();}
+collate(X) ::= COLLATE ids(I). {X = I;}
+collate ::= COLLATE ID_COLLATE. {}
+
+
+///////////////////////////// The DROP INDEX command /////////////////////////
+
+cmd(X) ::= DROP INDEX ifexists(I)
+ fullname(N). {
+ X = new SqliteDropIndex(*(I), N->name1, N->name2);
+ delete I;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP INDEX ifexists nm DOT ID_IDX. {}
+cmd ::= DROP INDEX ifexists ID_DB|ID_IDX. {}
+
+///////////////////////////// The VACUUM command /////////////////////////////
+
+cmd(X) ::= VACUUM. {
+ X = new SqliteVacuum();
+ objectForTokens = X;
+ }
+cmd(X) ::= VACUUM nm(N). {
+ X = new SqliteVacuum(*(N));
+ delete N;
+ objectForTokens = X;
+ }
+
+///////////////////////////// The PRAGMA command /////////////////////////////
+
+cmd(X) ::= PRAGMA nm(N1) dbnm(N2). {
+ X = new SqlitePragma(*(N1), *(N2));
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N1) dbnm(N2) EQ
+ nmnum(V). {
+ X = new SqlitePragma(*(N1), *(N2), *(V), true);
+ delete N1;
+ delete N2;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N1) dbnm(N2) LP
+ nmnum(V) RP. {
+ X = new SqlitePragma(*(N1), *(N2), *(V), false);
+ delete N1;
+ delete N2;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N1) dbnm(N2) EQ
+ minus_num(V). {
+ X = new SqlitePragma(*(N1), *(N2), *(V), true);
+ delete N1;
+ delete N2;
+ delete V;
+ objectForTokens = X;
+ }
+cmd(X) ::= PRAGMA nm(N1) dbnm(N2) LP
+ minus_num(V) RP. {
+ X = new SqlitePragma(*(N1), *(N2), *(V), false);
+ delete N1;
+ delete N2;
+ delete V;
+ objectForTokens = X;
+ }
+
+cmd ::= PRAGMA nm DOT ID_PRAGMA. {}
+cmd ::= PRAGMA ID_DB|ID_PRAGMA. {}
+
+%type nmnum {QVariant*}
+%destructor nmnum {delete $$;}
+nmnum(X) ::= plus_num(N). {X = N;}
+nmnum(X) ::= nm(N). {
+ X = new QVariant(*(N));
+ delete N;
+ }
+nmnum(X) ::= ON(T). {X = new QVariant(T->value);}
+nmnum(X) ::= DELETE(T). {X = new QVariant(T->value);}
+nmnum(X) ::= DEFAULT(T). {X = new QVariant(T->value);}
+
+%type plus_num {QVariant*}
+%destructor plus_num {delete $$;}
+plus_num(X) ::= PLUS number(N). {X = N;}
+plus_num(X) ::= number(N). {X = N;}
+
+%type minus_num {QVariant*}
+%destructor minus_num {delete $$;}
+minus_num(X) ::= MINUS number(N). {
+ if (N->type() == QVariant::Double)
+ *(N) = -(N->toDouble());
+ else if (N->type() == QVariant::LongLong)
+ *(N) = -(N->toLongLong());
+ else
+ Q_ASSERT_X(true, "producing minus number", "QVariant is neither of Double or LongLong.");
+
+ X = N;
+ }
+
+%type number {QVariant*}
+%destructor number {delete $$;}
+number(X) ::= INTEGER(N). {X = new QVariant(QVariant(N->value).toLongLong());}
+number(X) ::= FLOAT(N). {X = new QVariant(QVariant(N->value).toDouble());}
+
+//////////////////////////// The CREATE TRIGGER command /////////////////////
+
+// Sqlite grammar uses 'fullname' for table name, but it's forbidden anyway,
+// because you cannot create trigger for table in different database.
+// We use 'nm' instead, as it's more proper. Will see if it truns out to be a problem.
+cmd(X) ::= CREATE temp(T) TRIGGER
+ ifnotexists(IE) nm(N1) dbnm(N2)
+ trigger_time(TT) trigger_event(EV)
+ ON nm(N) foreach_clause(FC)
+ when_clause(WC) BEGIN
+ trigger_cmd_list(CL) END. {
+ X = new SqliteCreateTrigger(
+ *(T),
+ *(IE),
+ *(N1),
+ *(N2),
+ *(N),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ *(CL),
+ 3
+ );
+ delete IE;
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ delete CL;
+ objectForTokens = X;
+ }
+
+// Support full parsing when no BEGIN and END are present (for completion helper)
+cmd(X) ::= CREATE temp(T) TRIGGER
+ ifnotexists(IE) nm(N1) dbnm(N2)
+ trigger_time(TT) trigger_event(EV)
+ ON nm(N) foreach_clause(FC)
+ when_clause(WC). {
+ QList<SqliteQuery *> CL;
+
+ X = new SqliteCreateTrigger(
+ *(T),
+ *(IE),
+ *(N1),
+ *(N2),
+ *(N),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ CL,
+ 3
+ );
+ delete IE;
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+// Support full parsing when no END is present (for completion helper)
+cmd(X) ::= CREATE temp(T) TRIGGER
+ ifnotexists(IE) nm(N1) dbnm(N2)
+ trigger_time(TT) trigger_event(EV)
+ ON nm(N) foreach_clause(FC)
+ when_clause(WC) BEGIN
+ trigger_cmd_list(CL). {
+ X = new SqliteCreateTrigger(
+ *(T),
+ *(IE),
+ *(N1),
+ *(N2),
+ *(N),
+ *(TT),
+ EV,
+ *(FC),
+ WC,
+ *(CL),
+ 3
+ );
+ delete IE;
+ delete T;
+ delete TT;
+ delete FC;
+ delete N1;
+ delete N;
+ delete N2;
+ delete CL;
+ objectForTokens = X;
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+cmd ::= CREATE temp TRIGGER ifnotexists nm
+ dbnm trigger_time trigger_event
+ ON ID_TAB. {}
+cmd ::= CREATE temp TRIGGER ifnotexists nm
+ DOT ID_TRIG_NEW. {}
+cmd ::= CREATE temp TRIGGER ifnotexists
+ ID_DB|ID_TRIG_NEW. {}
+
+%type trigger_time {SqliteCreateTrigger::Time*}
+%destructor trigger_time {delete $$;}
+trigger_time(X) ::= BEFORE. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::BEFORE);}
+trigger_time(X) ::= AFTER. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::AFTER);}
+trigger_time(X) ::= INSTEAD OF. {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::INSTEAD_OF);}
+trigger_time(X) ::= . {X = new SqliteCreateTrigger::Time(SqliteCreateTrigger::Time::null);}
+
+%type trigger_event {SqliteCreateTrigger::Event*}
+%destructor trigger_event {delete $$;}
+trigger_event(X) ::= DELETE. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::DELETE);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= INSERT. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::INSERT);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= UPDATE. {
+ X = new SqliteCreateTrigger::Event(SqliteCreateTrigger::Event::UPDATE);
+ objectForTokens = X;
+ }
+trigger_event(X) ::= UPDATE OF
+ inscollist(L). {
+ X = new SqliteCreateTrigger::Event(*(L));
+ delete L;
+ objectForTokens = X;
+ }
+
+%type foreach_clause {SqliteCreateTrigger::Scope*}
+%destructor foreach_clause {delete $$;}
+foreach_clause(X) ::= . {X = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::null);}
+foreach_clause(X) ::= FOR EACH ROW. {X = new SqliteCreateTrigger::Scope(SqliteCreateTrigger::Scope::FOR_EACH_ROW);}
+
+%type when_clause {SqliteExpr*}
+%destructor when_clause {if ($$) delete $$;}
+when_clause(X) ::= . {X = nullptr;}
+when_clause(X) ::= WHEN expr(E). {X = E;}
+
+%type trigger_cmd_list {ParserQueryList*}
+%destructor trigger_cmd_list {delete $$;}
+trigger_cmd_list(X) ::= trigger_cmd_list(L)
+ trigger_cmd(C) SEMI. {
+ L->append(C);
+ X = L;
+ DONT_INHERIT_TOKENS("trigger_cmd_list");
+ }
+trigger_cmd_list(X) ::= trigger_cmd(C)
+ SEMI. {
+ X = new ParserQueryList();
+ X->append(C);
+ }
+trigger_cmd_list(X) ::= SEMI. {
+ X = new ParserQueryList();
+ parserContext->minorErrorAfterLastToken("Syntax error");
+ }
+
+%type trigger_cmd {SqliteQuery*}
+%destructor trigger_cmd {delete $$;}
+trigger_cmd(X) ::= update_stmt(S). {X = S;}
+trigger_cmd(X) ::= insert_stmt(S). {X = S;}
+trigger_cmd(X) ::= delete_stmt(S). {X = S;}
+trigger_cmd(X) ::= select_stmt(S). {X = S;}
+
+%type raisetype {Token*}
+raisetype(X) ::= ROLLBACK|ABORT|FAIL(V). {X = V;}
+
+
+//////////////////////// DROP TRIGGER statement //////////////////////////////
+cmd(X) ::= DROP TRIGGER ifexists(E)
+ fullname(N). {
+ X = new SqliteDropTrigger(*(E), N->name1, N->name2);
+ delete E;
+ delete N;
+ objectForTokens = X;
+ }
+
+cmd ::= DROP TRIGGER ifexists nm DOT
+ ID_TRIG. {}
+cmd ::= DROP TRIGGER ifexists
+ ID_DB|ID_TRIG. {}
+
+//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+cmd(X) ::= ATTACH database_kw_opt(D)
+ expr(E1) AS expr(E2) key_opt(K). {
+ X = new SqliteAttach(*(D), E1, E2, K);
+ delete D;
+ objectForTokens = X;
+ }
+cmd(X) ::= DETACH database_kw_opt(D)
+ expr(E). {
+ X = new SqliteDetach(*(D), E);
+ delete D;
+ objectForTokens = X;
+ }
+
+%type key_opt {SqliteExpr*}
+%destructor key_opt {if ($$) delete $$;}
+key_opt(X) ::= . {X = nullptr;}
+key_opt(X) ::= KEY expr(E). {X = E;}
+
+%type database_kw_opt {bool*}
+%destructor database_kw_opt {delete $$;}
+database_kw_opt(X) ::= DATABASE. {X = new bool(true);}
+database_kw_opt(X) ::= . {X = new bool(false);}
+
+////////////////////////// REINDEX collation //////////////////////////////////
+cmd(X) ::= REINDEX. {X = new SqliteReindex();}
+cmd(X) ::= REINDEX nm(N1) dbnm(N2). {
+ X = new SqliteReindex(*(N1), *(N2));
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ }
+
+cmd ::= REINDEX ID_COLLATE. {}
+cmd ::= REINDEX nm DOT ID_TAB|ID_IDX. {}
+cmd ::= REINDEX ID_DB|ID_IDX|ID_TAB. {}
+
+/////////////////////////////////// ANALYZE ///////////////////////////////////
+cmd(X) ::= ANALYZE. {
+ X = new SqliteAnalyze();
+ objectForTokens = X;
+ }
+cmd(X) ::= ANALYZE nm(N1) dbnm(N2). {
+ X = new SqliteAnalyze(*(N1), *(N2));
+ delete N1;
+ delete N2;
+ objectForTokens = X;
+ }
+
+cmd ::= ANALYZE nm DOT ID_TAB|ID_IDX. {}
+cmd ::= ANALYZE ID_DB|ID_IDX|ID_TAB. {}
+
+//////////////////////// ALTER TABLE table ... ////////////////////////////////
+cmd(X) ::= ALTER TABLE fullname(FN) RENAME
+ TO nm(N). {
+ X = new SqliteAlterTable(
+ FN->name1,
+ FN->name2,
+ *(N)
+ );
+ delete N;
+ delete FN;
+ objectForTokens = X;
+ }
+cmd(X) ::= ALTER TABLE fullname(FN) ADD
+ kwcolumn_opt(K) column(C). {
+ X = new SqliteAlterTable(
+ FN->name1,
+ FN->name2,
+ *(K),
+ C
+ );
+ delete K;
+ delete FN;
+ objectForTokens = X;
+ }
+
+cmd ::= ALTER TABLE fullname RENAME TO
+ ID_TAB_NEW. {}
+cmd ::= ALTER TABLE nm DOT ID_TAB. {}
+cmd ::= ALTER TABLE ID_DB|ID_TAB. {}
+
+%type kwcolumn_opt {bool*}
+%destructor kwcolumn_opt {delete $$;}
+kwcolumn_opt(X) ::= . {X = new bool(true);}
+kwcolumn_opt(X) ::= COLUMNKW. {X = new bool(false);}
+
+//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
+cmd(X) ::= create_vtab(C). {X = C;}
+
+%type create_vtab {SqliteQuery*}
+%destructor create_vtab {delete $$;}
+create_vtab(X) ::= CREATE VIRTUAL TABLE
+ ifnotexists(E) nm(N1)
+ dbnm(N2) USING nm(N3). {
+ X = new SqliteCreateVirtualTable(
+ *(E),
+ *(N1),
+ *(N2),
+ *(N3)
+ );
+ delete E;
+ delete N1;
+ delete N2;
+ delete N3;
+ objectForTokens = X;
+ }
+create_vtab(X) ::= CREATE VIRTUAL TABLE
+ ifnotexists(E) nm(N1)
+ dbnm(N2) USING nm(N3) LP
+ vtabarglist(A) RP. {
+ X = new SqliteCreateVirtualTable(
+ *(E),
+ *(N1),
+ *(N2),
+ *(N3),
+ *(A)
+ );
+ delete N1;
+ delete N2;
+ delete N3;
+ delete E;
+ delete A;
+ objectForTokens = X;
+ }
+
+create_vtab ::= CREATE VIRTUAL TABLE
+ ifnotexists nm DOT
+ ID_TAB_NEW. {}
+create_vtab ::= CREATE VIRTUAL TABLE
+ ifnotexists
+ ID_DB|ID_TAB_NEW. {}
+
+%type vtabarglist {ParserStringList*}
+%destructor vtabarglist {delete $$;}
+vtabarglist(X) ::= vtabarg(A). {
+ X = new ParserStringList();
+ X->append((A)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg
+ delete A;
+ }
+vtabarglist(X) ::= vtabarglist(L) COMMA
+ vtabarg(A). {
+ L->append((A)->mid(1)); // mid(1) to skip the first whitespace added in vtabarg
+ X = L;
+ delete A;
+ DONT_INHERIT_TOKENS("vtabarglist");
+ }
+
+%type vtabarg {QString*}
+%destructor vtabarg {delete $$;}
+vtabarg(X) ::= . {X = new QString();}
+vtabarg(X) ::= vtabarg(A) vtabargtoken(T). {
+ A->append(" "+ *(T));
+ X = A;
+ delete T;
+ }
+
+%type vtabargtoken {QString*}
+%destructor vtabargtoken {delete $$;}
+vtabargtoken(X) ::= ANY(A). {
+ X = new QString(A->value);
+ }
+vtabargtoken(X) ::= LP anylist(L) RP. {
+ X = new QString("(");
+ X->append(*(L));
+ X->append(")");
+ delete L;
+ }
+
+%type anylist {QString*}
+%destructor anylist {delete $$;}
+anylist(X) ::= . {X = new QString();}
+anylist(X) ::= anylist(L1) LP anylist(L2)
+ RP. {
+ X = L1;
+ X->append("(");
+ X->append(*(L2));
+ X->append(")");
+ delete L2;
+ DONT_INHERIT_TOKENS("anylist");
+ }
+anylist(X) ::= anylist(L) ANY(A). {
+ X = L;
+ X->append(A->value);
+ DONT_INHERIT_TOKENS("anylist");
+ }
+
+//////////////////////// COMMON TABLE EXPRESSIONS ////////////////////////////
+%type with {SqliteWith*}
+%type wqlist {SqliteWith*}
+%destructor with {delete $$;}
+%destructor wqlist {delete $$;}
+
+with(X) ::= . {X = nullptr;}
+with(X) ::= WITH wqlist(W). {
+ X = W;
+ objectForTokens = X;
+ }
+with(X) ::= WITH RECURSIVE wqlist(W). {
+ X = W;
+ X->recursive = true;
+ objectForTokens = X;
+ }
+
+wqlist(X) ::= nm(N) idxlist_opt(IL) AS
+ LP select(S) RP. {
+ X = SqliteWith::append(*(N), *(IL), S);
+ delete N;
+ delete IL;
+ }
+wqlist(X) ::= wqlist(WL) COMMA nm(N)
+ idxlist_opt(IL) AS
+ LP select(S) RP. {
+ X = SqliteWith::append(WL, *(N), *(IL), S);
+ delete N;
+ delete IL;
+ DONT_INHERIT_TOKENS("wqlist");
+ }
+wqlist(X) ::= ID_TAB_NEW. {
+ parserContext->minorErrorBeforeNextToken("Syntax error");
+ X = new SqliteWith();
+ }
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp
new file mode 100644
index 0000000..4f248b0
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.cpp
@@ -0,0 +1,206 @@
+#include "statementtokenbuilder.h"
+#include "parser/ast/sqlitestatement.h"
+#include "common/utils_sql.h"
+#include <QVariant>
+
+StatementTokenBuilder& StatementTokenBuilder::withKeyword(const QString& value)
+{
+ return with(Token::KEYWORD, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withOther(const QString& value)
+{
+ return with(Token::OTHER, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withOther(const QString& value, Dialect dialect)
+{
+ return withOther(wrapObjIfNeeded(value, dialect));
+}
+
+StatementTokenBuilder&StatementTokenBuilder::withStringPossiblyOther(const QString& value, Dialect dialect)
+{
+ if (value.contains("\""))
+ return withOther(wrapObjIfNeeded(value, dialect));
+ else
+ return withOther(wrapObjName(value, NameWrapper::DOUBLE_QUOTE));
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList<QString>& value, Dialect dialect, const QString& separator)
+{
+ bool first = true;
+ foreach (const QString& str, value)
+ {
+ if (!first)
+ {
+ if (!separator.isEmpty())
+ withOperator(separator);
+
+ withSpace();
+ }
+ withOther(str, dialect);
+ first = false;
+ }
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withOtherList(const QList<QString>& value, const QString& separator)
+{
+ bool first = true;
+ foreach (const QString& str, value)
+ {
+ if (!first)
+ {
+ if (!separator.isEmpty())
+ withOperator(separator);
+
+ withSpace();
+ }
+ withOther(str);
+ first = false;
+ }
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withOperator(const QString& value)
+{
+ return with(Token::OPERATOR, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withComment(const QString& value)
+{
+ return with(Token::COMMENT, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withFloat(double value)
+{
+ return with(Token::FLOAT, QString::number(value));
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withInteger(int value)
+{
+ return with(Token::INTEGER, QString::number(value));
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withBindParam(const QString& value)
+{
+ return with(Token::BIND_PARAM, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withParLeft()
+{
+ return with(Token::PAR_LEFT, "(");
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withParRight()
+{
+ return with(Token::PAR_RIGHT, ")");
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withSpace()
+{
+ return with(Token::SPACE, " ");
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withBlob(const QString& value)
+{
+ return with(Token::BLOB, value);
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withString(const QString& value)
+{
+ return with(Token::STRING, wrapStringIfNeeded(value));
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withConflict(SqliteConflictAlgo onConflict)
+{
+ if (onConflict != SqliteConflictAlgo::null)
+ return withSpace().withKeyword("ON").withSpace().withKeyword("CONFLICT")
+ .withSpace().withKeyword(sqliteConflictAlgo(onConflict));
+
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withSortOrder(SqliteSortOrder sortOrder)
+{
+ if (sortOrder != SqliteSortOrder::null)
+ return withSpace().withKeyword(sqliteSortOrder(sortOrder));
+
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withStatement(SqliteStatement* stmt)
+{
+ if (!stmt)
+ return *this;
+
+ stmt->rebuildTokens();
+ if (stmt->tokens.size() > 0)
+ {
+ if (tokens.size() > 0 && !tokens.last()->isWhitespace() && tokens.last()->type != Token::PAR_LEFT)
+ withSpace();
+
+ tokens += stmt->tokens;
+ tokens.trimRight(Token::OPERATOR, ";");
+ }
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withTokens(TokenList tokens)
+{
+ this->tokens += tokens;
+ return *this;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::withLiteralValue(const QVariant& value)
+{
+ if (value.isNull())
+ return *this;
+
+ bool ok;
+ if (value.userType() == QVariant::Double)
+ {
+ value.toDouble(&ok);
+ if (ok)
+ {
+ withFloat(value.toDouble());
+ return *this;
+ }
+ }
+
+ value.toInt(&ok);
+ if (ok)
+ {
+ withInteger(value.toInt());
+ return *this;
+ }
+
+ QString str = value.toString();
+ if (str.startsWith("x'", Qt::CaseInsensitive) && str.endsWith("'"))
+ {
+ withBlob(str);
+ return *this;
+ }
+
+ withString(str);
+ return *this;
+}
+
+TokenList StatementTokenBuilder::build() const
+{
+ return tokens;
+}
+
+void StatementTokenBuilder::clear()
+{
+ tokens.clear();
+ currentIdx = 0;
+}
+
+StatementTokenBuilder& StatementTokenBuilder::with(Token::Type type, const QString& value)
+{
+ int size = value.size();
+ tokens << TokenPtr::create(type, value, currentIdx, currentIdx + size - 1);
+ currentIdx += size;
+ return *this;
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h
new file mode 100644
index 0000000..fcf23be
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/statementtokenbuilder.h
@@ -0,0 +1,290 @@
+#ifndef STATEMENTTOKENBUILDER_H
+#define STATEMENTTOKENBUILDER_H
+
+#include "token.h"
+#include "ast/sqliteconflictalgo.h"
+#include "ast/sqlitesortorder.h"
+#include "dialect.h"
+
+class SqliteStatement;
+
+/**
+ * @brief Builder producing token list basing on certain inputs.
+ *
+ * This builder provides several methods to build list of tokens from various input values. It can produce
+ * token list for entire AST objects, or it can produce token list for list of names, etc.
+ *
+ * Token builder is used in SqliteStatement derived classes to rebuild SqliteStatement::tokens basing on the
+ * values in their class members.
+ *
+ * Typical use case:
+ * @code
+ * TokenList SqliteCreateView::rebuildTokensFromContents()
+ * {
+ * StatementTokenBuilder builder;
+ *
+ * builder.withKeyword("CREATE").withSpace();
+ * if (tempKw)
+ * builder.withKeyword("TEMP").withSpace();
+ * else if (temporaryKw)
+ * builder.withKeyword("TEMPORARY").withSpace();
+ *
+ * builder.withKeyword("VIEW").withSpace();
+ * if (ifNotExists)
+ * builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
+ *
+ * if (dialect == Dialect::Sqlite3 && !database.isNull())
+ * builder.withOther(database, dialect).withOperator(".");
+ *
+ * builder.withOther(view, dialect).withSpace().withKeyword("AS").withStatement(select);
+ *
+ * return builder.build();
+ * }
+ * @endcode
+ */
+class StatementTokenBuilder
+{
+ public:
+ /**
+ * @brief Adds keyword token.
+ * @param value Value of the keyword token.
+ * @return Reference to the builder for the further building.
+ *
+ * Keyword \p value gets converted to upper case.
+ */
+ StatementTokenBuilder& withKeyword(const QString& value);
+
+ /**
+ * @brief Adds "other" token (some object name, or other word).
+ * @param value Value for the token.
+ * @return Reference to the builder for the further building.
+ *
+ * This is used for table names, etc. The \p value is quoted just as passed.
+ */
+ StatementTokenBuilder& withOther(const QString& value);
+
+ /**
+ * @brief Adds "other" token (some object name, or other word).
+ * @param value Value for the token.
+ * @param dialect Dialect used for wrapping the value.
+ * @return Reference to the builder for the further building.
+ *
+ * The \p value is wrapped with the proper wrapper using wrapObjIfNeeded().
+ *
+ * @overload
+ */
+ StatementTokenBuilder& withOther(const QString& value, Dialect dialect);
+
+ /**
+ * @brief Adds string using double-quote wrapping.
+ * @param value Value for the token.
+ * @param dialect Dialect used for wrapping the value if double-quote could not be used.
+ * @return Reference to the builder for the further building.
+ *
+ * The \p value is wrapped with double quote, but if it's not possible then the proper wrapper is used by wrapObjIfNeeded().
+ *
+ * @overload
+ */
+ StatementTokenBuilder& withStringPossiblyOther(const QString& value, Dialect dialect);
+
+ /**
+ * @brief Adds list of "other" tokens.
+ * @param value List of values for tokens.
+ * @param dialect Dialect used for wrapping values.
+ * @param separator Optional value for separator tokens.
+ * @return Reference to the builder for the further building.
+ *
+ * Given the input \p value, this method produces list of tokens. Additionally it can put extra separator
+ * token between all produced tokens using the \p separator value. To skip separator tokens pass
+ * an empty string as the separator value.
+ */
+ StatementTokenBuilder& withOtherList(const QList<QString>& value, Dialect dialect, const QString& separator = ",");
+
+ /**
+ * @brief Adds list of "other" tokens.
+ * @param value List of values for tokens.
+ * @param separator Optional value for separator tokens.
+ * @return Reference to the builder for the further building.
+ *
+ * Works just like the other withOtherList() method, except it doesn't wrap values with wrapObjIfNeeded().
+ *
+ * @overload
+ */
+ StatementTokenBuilder& withOtherList(const QList<QString>& value, const QString& separator = ",");
+
+ /**
+ * @brief Adds operator token.
+ * @param value Value of the operator (";", "+", etc).
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withOperator(const QString& value);
+
+ /**
+ * @brief Adds comment token.
+ * @param value Comment value, including start/end characters of the comment.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withComment(const QString& value);
+
+ /**
+ * @brief Adds decimal number token.
+ * @param value Value for the token.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withFloat(double value);
+
+ /**
+ * @brief Add integer numer token.
+ * @param value Value for the token.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withInteger(int value);
+
+ /**
+ * @brief Adds bind parameter token.
+ * @param value Name of the bind parameter, including ":" or "@" at the begining.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withBindParam(const QString& value);
+
+ /**
+ * @brief Adds left parenthesis token (<tt>"("</tt>).
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withParLeft();
+
+ /**
+ * @brief Adds right parenthesis token (<tt>")"</tt>).
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withParRight();
+
+ /**
+ * @brief Adds a single whitespace token.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withSpace();
+
+ /**
+ * @brief Adds BLOB value token.
+ * @param value BLOB value for the token.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withBlob(const QString& value);
+
+ /**
+ * @brief Adds string value token.
+ * @param value Value for the token.
+ * @return Reference to the builder for the further building.
+ *
+ * The string is wrapped with single quote characters if it's not wrapped yet.
+ */
+ StatementTokenBuilder& withString(const QString& value);
+
+ /**
+ * @brief Adds set of tokens represeting "ON CONFLICT" statement.
+ * @param onConflict Conflict resolution algorithm to build for.
+ * @return Reference to the builder for the further building.
+ *
+ * If algorithm is SqliteConflictAlgo::null, no tokens are added.
+ */
+ StatementTokenBuilder& withConflict(SqliteConflictAlgo onConflict);
+
+ /**
+ * @brief Adds space and <tt>"ASC"/"DESC"</tt> token.
+ * @param sortOrder Sort order to use.
+ * @return Reference to the builder for the further building.
+ *
+ * If the sort order is SqliteSortOrder::null, no tokens are added.
+ */
+ StatementTokenBuilder& withSortOrder(SqliteSortOrder sortOrder);
+
+ /**
+ * @brief Adds set of tokens representing entire statement.
+ * @param stmt Statement to add tokens for.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withStatement(SqliteStatement* stmt);
+
+ /**
+ * @brief Adds already defined list of tokens to this builder.
+ * @param tokens Tokens to add.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& withTokens(TokenList tokens);
+
+ /**
+ * @brief Adds literal value token (integer, decimal, string, BLOB).
+ * @param value Value for the token.
+ * @return Reference to the builder for the further building.
+ *
+ * This method tries to convert given \p value to integer,
+ * then to double, then it checks if the value has format <tt>X'...'</tt>
+ * and if if succeeded at any of those steps, then it adds appropriate
+ * token. If none of above succeeded, then the string token is added.
+ */
+ StatementTokenBuilder& withLiteralValue(const QVariant& value);
+
+ /**
+ * @brief Adds tokens representing list of entire statements.
+ * @param stmtList List of statements to add tokens for.
+ * @param separator Optional separator to be used for separator tokens.
+ * @return Reference to the builder for the further building.
+ *
+ * This method is very similar to withOtherList(), except it works
+ * on the entire statements.
+ */
+ template <class T>
+ StatementTokenBuilder& withStatementList(QList<T*> stmtList, const QString& separator = ",")
+ {
+ bool first = true;
+ foreach (T* stmt, stmtList)
+ {
+ if (!first)
+ {
+ if (!separator.isEmpty())
+ withOperator(separator);
+
+ withSpace();
+ }
+ withStatement(stmt);
+ first = false;
+ }
+ return *this;
+ }
+
+ /**
+ * @brief Provides all tokens added so far as a compat token list.
+ * @return List of tokens built so far.
+ */
+ TokenList build() const;
+
+ /**
+ * @brief Cleans up all tokens added so far.
+ */
+ void clear();
+
+ private:
+ /**
+ * @brief Adds token of given type and value.
+ * @param type Type of the token to add.
+ * @param value Value for the token to add.
+ * @return Reference to the builder for the further building.
+ */
+ StatementTokenBuilder& with(Token::Type type, const QString& value);
+
+ /**
+ * @brief List of tokens added so far.
+ */
+ TokenList tokens;
+
+ /**
+ * @brief Current character position index.
+ *
+ * This index is used to generate proper values for Token::start and Token::end.
+ * Each added token increments this index by the value length.
+ */
+ int currentIdx = 0;
+};
+
+#endif // STATEMENTTOKENBUILDER_H
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp
new file mode 100644
index 0000000..5e186dd
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.cpp
@@ -0,0 +1,621 @@
+#include "token.h"
+#include "lexer.h"
+#include <stdio.h>
+#include <QStringList>
+
+Token::Token()
+ : lemonType(0), type(INVALID), value(QString::null), start(-1), end(-1)
+{
+}
+
+Token::Token(int lemonType, Type type, QString value, qint64 start, qint64 end)
+ : lemonType(lemonType), type(type), value(value), start(start), end(end)
+{}
+
+Token::Token(int lemonType, Type type, QChar value, qint64 start, qint64 end)
+ : lemonType(lemonType), type(type), value(value), start(start), end(end)
+{}
+
+Token::Token(int lemonType, Token::Type type, QString value)
+ : lemonType(lemonType), type(type), value(value), start(-1), end(-1)
+{
+}
+
+Token::Token(QString value)
+ : lemonType(0), type(INVALID), value(value), start(0), end(0)
+{}
+
+Token::Token(Token::Type type, QString value)
+ : lemonType(0), type(type), value(value), start(0), end(0)
+{
+}
+
+Token::Token(Token::Type type, QString value, qint64 start, qint64 end)
+ : lemonType(0), type(type), value(value), start(start), end(end)
+{
+}
+
+Token::~Token()
+{
+}
+
+QString Token::toString()
+{
+ return "{" +
+ typeToString(type) +
+ " " +
+ value +
+ " " +
+ QString::number(start) +
+ " " +
+ QString::number(end) +
+ "}";
+}
+
+const QString Token::typeToString(Token::Type type)
+{
+ switch (type)
+ {
+ case Token::CTX_ROWID_KW:
+ return "CTX_ROWID_KW";
+ case Token::CTX_NEW_KW:
+ return "CTX_NEW_KW";
+ case Token::CTX_OLD_KW:
+ return "CTX_OLD_KW";
+ case Token::CTX_TABLE_NEW:
+ return "CTX_TABLE_NEW";
+ case Token::CTX_INDEX_NEW:
+ return "CTX_INDEX_NEW";
+ case Token::CTX_VIEW_NEW:
+ return "CTX_VIEW_NEW";
+ case Token::CTX_TRIGGER_NEW:
+ return "CTX_TRIGGER_NEW";
+ case Token::CTX_ALIAS:
+ return "CTX_ALIAS";
+ case Token::CTX_TRANSACTION:
+ return "CTX_transaction";
+ case Token::CTX_COLUMN_NEW:
+ return "CTX_COLUMN_NEW";
+ case Token::CTX_COLUMN_TYPE:
+ return "CTX_COLUMN_TYPE";
+ case Token::CTX_CONSTRAINT:
+ return "CTX_CONSTRAINT";
+ case Token::CTX_FK_MATCH:
+ return "CTX_FK_MATCH";
+ case Token::CTX_PRAGMA:
+ return "CTX_PRAGMA";
+ case Token::CTX_ERROR_MESSAGE:
+ return "CTX_ERROR_MESSAGE";
+ case Token::CTX_COLUMN:
+ return "CTX_COLUMN";
+ case Token::CTX_TABLE:
+ return "CTX_TABLE";
+ case Token::CTX_DATABASE:
+ return "CTX_DATABASE";
+ case Token::CTX_FUNCTION:
+ return "CTX_FUNCTION";
+ case Token::CTX_COLLATION:
+ return "CTX_COLLATION";
+ case Token::CTX_INDEX:
+ return "CTX_INDEX";
+ case Token::CTX_TRIGGER:
+ return "CTX_TRIGGER";
+ case Token::CTX_VIEW:
+ return "CTX_VIEW";
+ case Token::CTX_JOIN_OPTS:
+ return "CTX_JOIN_OPTS";
+ case Token::INVALID:
+ return "INVALID";
+ case Token::OTHER:
+ return "OTHER";
+ case Token::STRING:
+ return "STRING";
+ case Token::COMMENT:
+ return "COMMENT";
+ case Token::FLOAT:
+ return "FLOAT";
+ case Token::INTEGER:
+ return "INTEGER";
+ case Token::BIND_PARAM:
+ return "BIND_PARAM";
+ case Token::OPERATOR:
+ return "OPERATOR";
+ case Token::PAR_LEFT:
+ return "PAR_LEFT";
+ case Token::PAR_RIGHT:
+ return "PAR_RIGHT";
+ case Token::SPACE:
+ return "SPACE";
+ case Token::BLOB:
+ return "BLOB";
+ case Token::KEYWORD:
+ return "KEYWORD";
+ }
+
+ return "";
+}
+
+Range Token::getRange()
+{
+ return Range(start, end);
+}
+
+bool Token::isWhitespace() const
+{
+ return (type == SPACE || type == COMMENT);
+}
+
+bool Token::isSeparating() const
+{
+ switch (type)
+ {
+ case Token::SPACE:
+ case Token::PAR_LEFT:
+ case Token::PAR_RIGHT:
+ case Token::OPERATOR:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Token::isDbObjectType() const
+{
+ return ((type & TOKEN_TYPE_MASK_DB_OBJECT) == TOKEN_TYPE_MASK_DB_OBJECT);
+}
+
+QString Token::typeString() const
+{
+ return typeToString(type);
+}
+
+int Token::operator ==(const Token &other)
+{
+ return type == other.type && value == other.value && start == other.start && end == other.end;
+}
+
+bool Token::operator <(const Token &other) const
+{
+ if (start == other.start)
+ return end < other.end;
+ else
+ return start < other.start;
+}
+
+uint qHash(const TokenPtr& token)
+{
+ // This doesn't look nice, but it's good enough to satisfy a hash table.
+ // It's fast and quite distinguishable.
+ // It's rare to have two pointers with the same int type representation,
+ // and if that happens, there's always a comparision operator.
+ return (uint)reinterpret_cast<qint64>(token.data());
+}
+
+TokenList::TokenList()
+ : QList<TokenPtr>()
+{
+}
+
+TokenList::TokenList(const QList<TokenPtr>& other)
+ : QList<TokenPtr>(other)
+{
+}
+
+QString TokenList::toString() const
+{
+ return toStringList().join(" ");
+}
+
+QStringList TokenList::toStringList() const
+{
+ QStringList strList;
+ TokenPtr t;
+ foreach (t, *this)
+ strList << t->toString();
+
+ return strList;
+}
+
+int TokenList::indexOf(TokenPtr token) const
+{
+ return QList<TokenPtr>::indexOf(token);
+}
+
+int TokenList::indexOf(Token::Type type) const
+{
+ int i;
+ findFirst(type, &i);
+ return i;
+}
+
+int TokenList::indexOf(Token::Type type, const QString &value, Qt::CaseSensitivity caseSensitivity) const
+{
+ int i;
+ findFirst(type, value, caseSensitivity, &i);
+ return i;
+}
+
+int TokenList::indexOf(const QString &value, Qt::CaseSensitivity caseSensitivity) const
+{
+ int i;
+ findFirst(value, caseSensitivity, &i);
+ return i;
+}
+
+int TokenList::lastIndexOf(TokenPtr token) const
+{
+ return QList<TokenPtr>::lastIndexOf(token);
+}
+
+int TokenList::lastIndexOf(Token::Type type) const
+{
+ int i;
+ findLast(type, &i);
+ return i;
+}
+
+int TokenList::lastIndexOf(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity) const
+{
+ int i;
+ findLast(type, value, caseSensitivity, &i);
+ return i;
+}
+
+int TokenList::lastIndexOf(const QString& value, Qt::CaseSensitivity caseSensitivity) const
+{
+ int i;
+ findLast(value, caseSensitivity, &i);
+ return i;
+}
+
+TokenPtr TokenList::find(Token::Type type) const
+{
+ return findFirst(type, nullptr);
+}
+
+TokenPtr TokenList::find(Token::Type type, const QString &value, Qt::CaseSensitivity caseSensitivity) const
+{
+ return findFirst(type, value, caseSensitivity, nullptr);
+}
+
+TokenPtr TokenList::find(const QString &value, Qt::CaseSensitivity caseSensitivity) const
+{
+ return findFirst(value, caseSensitivity, nullptr);
+}
+
+TokenPtr TokenList::findLast(Token::Type type) const
+{
+ return findLast(type, nullptr);
+}
+
+TokenPtr TokenList::findLast(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity) const
+{
+ return findLast(type, value, caseSensitivity, nullptr);
+}
+
+TokenPtr TokenList::findLast(const QString& value, Qt::CaseSensitivity caseSensitivity) const
+{
+ return findLast(value, caseSensitivity, nullptr);
+}
+
+TokenPtr TokenList::atCursorPosition(quint64 cursorPosition) const
+{
+ foreach (TokenPtr token, *this)
+ {
+ if (token->getRange().contains(cursorPosition))
+ return token;
+ }
+ return TokenPtr();
+}
+
+void TokenList::insert(int i, const TokenList &list)
+{
+ foreach (TokenPtr token, list)
+ QList<TokenPtr>::insert(i++, token);
+}
+
+void TokenList::insert(int i, TokenPtr token)
+{
+ QList<TokenPtr>::insert(i, token);
+}
+
+TokenList &TokenList::operator =(const QList<TokenPtr> &other)
+{
+ QList<TokenPtr>::operator =(other);
+ return *this;
+}
+
+QString TokenList::detokenize() const
+{
+ return Lexer::detokenize(*this);
+}
+
+void TokenList::replace(int startIdx, int length, const TokenList& newTokens)
+{
+ for (int i = 0; i < length; i++)
+ removeAt(startIdx);
+
+ insert(startIdx, newTokens);
+}
+
+void TokenList::replace(int startIdx, int length, TokenPtr newToken)
+{
+ for (int i = 0; i < length; i++)
+ removeAt(startIdx);
+
+ insert(startIdx, newToken);
+}
+
+void TokenList::replace(int startIdx, TokenPtr newToken)
+{
+ QList<TokenPtr>::replace(startIdx, newToken);
+}
+
+void TokenList::replace(int startIdx, const TokenList& newTokens)
+{
+ replace(startIdx, 1, newTokens);
+}
+
+int TokenList::replace(TokenPtr startToken, TokenPtr endToken, const TokenList& newTokens)
+{
+ int startIdx = indexOf(startToken);
+ if (startIdx < 0)
+ return 0;
+
+ int endIdx = indexOf(endToken);
+ if (endIdx < 0)
+ return 0;
+
+ replace(startIdx, endIdx - startIdx, newTokens);
+ return endIdx - startIdx;
+}
+
+int TokenList::replace(TokenPtr startToken, TokenPtr endToken, TokenPtr newToken)
+{
+ int startIdx = indexOf(startToken);
+ if (startIdx < 0)
+ return 0;
+
+ int endIdx = indexOf(endToken);
+ if (endIdx < 0)
+ return 0;
+
+ replace(startIdx, endIdx - startIdx, newToken);
+ return endIdx - startIdx;
+}
+
+bool TokenList::replace(TokenPtr oldToken, TokenPtr newToken)
+{
+ int idx = indexOf(oldToken);
+ if (idx < 0)
+ return false;
+
+ replace(idx, newToken);
+ return true;
+}
+
+bool TokenList::replace(TokenPtr oldToken, const TokenList& newTokens)
+{
+ int idx = indexOf(oldToken);
+ if (idx < 0)
+ return false;
+
+ replace(idx, newTokens);
+ return true;
+}
+
+bool TokenList::remove(TokenPtr startToken, TokenPtr endToken)
+{
+ int startIdx = indexOf(startToken);
+ if (startIdx < 0)
+ return false;
+
+ int endIdx = indexOf(endToken);
+ if (endIdx < 0)
+ return false;
+
+ if (endIdx < startIdx)
+ return false;
+
+ for (int i = startIdx; i < endIdx; i++)
+ removeAt(startIdx);
+
+ return true;
+}
+
+bool TokenList::remove(Token::Type type)
+{
+ int idx = indexOf(type);
+ if (idx == -1)
+ return false;
+
+ removeAt(idx);
+ return true;
+}
+
+void TokenList::trimLeft()
+{
+ while (size() > 0 && first()->isWhitespace())
+ removeFirst();
+}
+
+void TokenList::trimRight()
+{
+ while (size() > 0 && last()->isWhitespace())
+ removeLast();
+}
+
+void TokenList::trim()
+{
+ trimLeft();
+ trimRight();
+}
+
+void TokenList::trimLeft(Token::Type type, const QString& alsoTrim)
+{
+ while (size() > 0 && (first()->isWhitespace() || (first()->type == type && first()->value == alsoTrim)))
+ removeFirst();
+}
+
+void TokenList::trimRight(Token::Type type, const QString& alsoTrim)
+{
+ while (size() > 0 && (last()->isWhitespace() || (last()->type == type && last()->value == alsoTrim)))
+ removeLast();
+}
+
+void TokenList::trim(Token::Type type, const QString& alsoTrim)
+{
+ trimLeft(type, alsoTrim);
+ trimRight(type, alsoTrim);
+}
+
+TokenList TokenList::filter(Token::Type type) const
+{
+ TokenList filtered;
+ foreach (TokenPtr token, *this)
+ if (token->type == type)
+ filtered << token;
+
+ return filtered;
+}
+
+TokenList TokenList::filterWhiteSpaces() const
+{
+ TokenList filtered;
+ foreach (TokenPtr token, *this)
+ if (!token->isWhitespace())
+ filtered << token;
+
+ return filtered;
+}
+
+TokenList TokenList::mid(int pos, int length) const
+{
+ TokenList newList = QList<TokenPtr>::mid(pos, length);
+ return newList;
+}
+
+TokenPtr TokenList::findFirst(Token::Type type, int *idx) const
+{
+ int i = -1;
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ while (it.hasNext())
+ {
+ token = it.next();
+ i++;
+ if (token->type == type)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
+
+TokenPtr TokenList::findFirst(Token::Type type, const QString &value, Qt::CaseSensitivity caseSensitivity, int *idx) const
+{
+ int i = -1;
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ while (it.hasNext())
+ {
+ token = it.next();
+ i++;
+ if (token->type != type)
+ continue;
+
+ if (token->value.compare(value, caseSensitivity) == 0)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
+
+TokenPtr TokenList::findFirst(const QString &value, Qt::CaseSensitivity caseSensitivity, int *idx) const
+{
+ int i = -1;
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ while (it.hasNext())
+ {
+ token = it.next();
+ i++;
+ if (token->value.compare(value, caseSensitivity) == 0)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
+
+
+TokenPtr TokenList::findLast(Token::Type type, int* idx) const
+{
+ int i = size();
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ it.toBack();
+ while (it.hasPrevious())
+ {
+ token = it.previous();
+ i--;
+ if (token->type == type)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
+
+TokenPtr TokenList::findLast(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const
+{
+ int i = size();
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ it.toBack();
+ while (it.hasPrevious())
+ {
+ token = it.previous();
+ i--;
+ if (token->type != type)
+ continue;
+
+ if (token->value.compare(value, caseSensitivity) == 0)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
+
+TokenPtr TokenList::findLast(const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const
+{
+ int i = size();
+ TokenPtr token;
+ QListIterator<TokenPtr> it(*this);
+ it.toBack();
+ while (it.hasPrevious())
+ {
+ token = it.previous();
+ i--;
+ if (token->value.compare(value, caseSensitivity) == 0)
+ {
+ if (idx) (*idx) = i;
+ return token;
+ }
+ }
+ if (idx) (*idx) = -1;
+ return TokenPtr();
+}
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/token.h b/SQLiteStudio3/coreSQLiteStudio/parser/token.h
new file mode 100644
index 0000000..1090bd4
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/token.h
@@ -0,0 +1,733 @@
+#ifndef TOKEN_H
+#define TOKEN_H
+
+#include "common/utils.h"
+#include <QString>
+#include <QList>
+#include <QSharedPointer>
+
+/** @file */
+
+/**
+ * @def TOKEN_TYPE_MASK_DB_OBJECT
+ *
+ * Bit mask used to test Token::Type for representing any database object name, in any form.
+ * It's used in Token::isDbObjectType().
+ */
+#define TOKEN_TYPE_MASK_DB_OBJECT 0x1000
+
+struct Token;
+
+/**
+ * @brief Shared pointer to the Token.
+ */
+typedef QSharedPointer<Token> TokenPtr;
+
+/**
+ * @brief SQL query entity representing isolated part of the query.
+ *
+ * Tokens are generated by Lexer. Each token represents isolated part of the query,
+ * like a name, a number, an operator, a string, a keyword, or a comment, etc.
+ *
+ * In other words, tokenizing SQL query is splitting it into logical parts.
+ *
+ * Each token has a type, a value and position indexes of where it starts and where it ends (in the query string).
+ *
+ * Tokens are used mainly by the Parser to perform syntax analysis, but they can be also very helpful
+ * in other areas. They provide easy way for safe manipulation on the query string, without worrying
+ * about counting open or close characters of the string, etc. If the string has a single-quote used twice inside,
+ * this is still a regular SQL string and in that case there will be only a single string token representing it.
+ *
+ * If you're constructing Token outside of the Lemon parser, you should be interested only in 4 constructors:
+ * Token(), Token(QString value), Token(Type type, QString value)
+ * and Token(Type type, QString value, qint64 start, qint64 end).
+ * Rest of the constructors are to be used from the Lemon parser, as they require Lemon token ID to be provided.
+ *
+ * You will usually have the most to do with tokens when dealing with SqliteStatement and its 2 members:
+ * SqliteStatement::tokens and SqliteStatement::tokenMap.
+ */
+struct API_EXPORT Token
+{
+ /**
+ * @brief Token type.
+ *
+ * There are 2 kind of types - regular and context-oriented.
+ *
+ * Regular types are those defined by the SQL grammar and they represent real tokens. A special token type
+ * from group of regular types is the Type::INVALID, which means, that the character(s) encountered
+ * by the Lexer are invalid in SQL syntax understanding, or when there was no more query characters to read
+ * (which in this case means that tokenizing ended before this token).
+ *
+ * The context-oriented types are special meta types used by the Parser to probe potential candidates
+ * for next valid token when Parser::getNextTokenCandidates() is called. They are then processed by
+ * CompletionHelper. You won't deal with this kind of token types on regular basis. Context-oriented
+ * types are those starting with <tt>CTX_</tt>.
+ */
+ enum Type
+ {
+ INVALID = 0x0001, /**< Invalid token, or no more tokens available from Lexer. */
+ OTHER = 0x1002, /**< A name, a word. */
+ STRING = 0x0003, /**< A string (value will be stripped of the surrounding quotes). */
+ COMMENT = 0x0004, /**< A comment, including starting/ending markers. */
+ FLOAT = 0x0005, /**< A decimal number. */
+ INTEGER = 0x0006, /**< An integer number. */
+ BIND_PARAM = 0x0007, /**< A bind parameter (<tt>:param</tt>, <tt>\@param</tt>, or <tt>?</tt>). */
+ OPERATOR = 0x0008, /**< An operator (like <tt>";"</tt>, <tt>"+"</tt>, <tt>","</tt>, etc). */
+ PAR_LEFT = 0x0009, /**< A left parenthesis (<tt>"("</tt>). */
+ PAR_RIGHT = 0x0010, /**< A right parenthesis (<tt>")"</tt>). */
+ SPACE = 0x0011, /**< White space(s), including new line characters and tabs. */
+ BLOB = 0x0012, /**< Literal BLOB value (<tt>X'...'</tt> or <tt>x'...'</tt>). */
+ KEYWORD = 0x0013, /**< A keyword (see getKeywords3() and getKeywords2()). */
+ CTX_COLUMN = 0x1014, /**< Existing column name is valid at this token position. */
+ CTX_TABLE = 0x1015, /**< Existing table name is valid at this token potision. */
+ CTX_DATABASE = 0x1016, /**< Database name is valid at this token position. */
+ CTX_FUNCTION = 0x0017, /**< Function name is valid at this token position. */
+ CTX_COLLATION = 0x0018, /**< Collation name is valid at this token position. */
+ CTX_INDEX = 0x1019, /**< Existing index name is valid at this token position. */
+ CTX_TRIGGER = 0x1020, /**< Existing trigger name is valid at this token position. */
+ CTX_VIEW = 0x1021, /**< View name is valid at this token position. */
+ CTX_JOIN_OPTS = 0x0022, /**< JOIN keywords are valid at this token position (see getJoinKeywords()). */
+ CTX_TABLE_NEW = 0x0023, /**< Name for new table is valid at this token position. */
+ CTX_INDEX_NEW = 0x0024, /**< Name for new index is valid at this token position. */
+ CTX_VIEW_NEW = 0x0025, /**< Name for new view is valid at this token position. */
+ CTX_TRIGGER_NEW = 0x0026, /**< Name for new trigger is valid at this token position. */
+ CTX_ALIAS = 0x0027, /**< Alias name is valid at this token position. */
+ CTX_TRANSACTION = 0x0028, /**< Transaction name is valid at this token position. */
+ CTX_COLUMN_NEW = 0x0029, /**< Name for the new column is valid at this token position. */
+ CTX_COLUMN_TYPE = 0x0030, /**< Data type for the new column is valid at this token position. */
+ CTX_CONSTRAINT = 0x0031, /**< Name for the new constraint is valid at this token position. */
+ CTX_FK_MATCH = 0x0032, /**< MATCH keywords are valid at this token position (see getFkMatchKeywords()). */
+ CTX_PRAGMA = 0x0033, /**< Pragma name is valid at this token position. */
+ CTX_ROWID_KW = 0x0034, /**< ROWID keywords is valid at this token position (see isRowIdKeyword()). */
+ CTX_NEW_KW = 0x0035, /**< The <tt>NEW</tt> keyword is valid at this token position. */
+ CTX_OLD_KW = 0x0036, /**< The <tt>OLD</tt> keyword is valid at this token position. */
+ CTX_ERROR_MESSAGE = 0x0037 /**< Error message string is valid at this token position. */
+ };
+
+ /**
+ * @brief Creates empty token with type Type::INVALID.
+ *
+ * Lemon token ID is set to 0 and start/end positions are set to -1.
+ */
+ Token();
+
+ /**
+ * @brief Creates fully defined token.
+ * @param lemonType Lemon token ID to use (see sqlite2_parser.h and sqlite3_parser.h).
+ * @param type Token type.
+ * @param value Value of the token.
+ * @param start Start position of the token (index of the first character in the query).
+ * @param end End position of the token (index of last character in the query).
+ *
+ * This constructor is intended to be used from Lemon parser only. For other use cases
+ * use constructors without the \p lemonType parameter, unless you need it and you know what you're doing.
+ */
+ Token(int lemonType, Type type, QString value, qint64 start, qint64 end);
+
+ /**
+ * @overload
+ */
+ Token(int lemonType, Type type, QChar value, qint64 start, qint64 end);
+
+ /**
+ * @overload
+ */
+ Token(int lemonType, Type type, QString value);
+
+ /**
+ * @brief Creates token with type Type::INVALID and given value.
+ * @param value Value for the token.
+ *
+ * Start/end positions are set to -1.
+ */
+ explicit Token(QString value);
+
+ /**
+ * @brief Creates token of given type and with given value.
+ * @param type Type for the token.
+ * @param value Value for the token.
+ *
+ * Start/end positions are set to -1.
+ */
+ Token(Type type, QString value);
+
+ /**
+ * @brief Creates fully defined token.
+ * @param type Type of the token.
+ * @param value Value for the token.
+ * @param start Start position of the token (index of the first character in the query).
+ * @param end End position of the token (index of last character in the query).
+ */
+ Token(Type type, QString value, qint64 start, qint64 end);
+
+ /**
+ * @brief Destructor declared as virtual. Does nothing in this implementation.
+ */
+ virtual ~Token();
+
+ /**
+ * @brief Serializes token to human readable form.
+ * @return Token values in format: <tt>{type value start end}</tt>
+ */
+ QString toString();
+
+ /**
+ * @brief Converts given token type into its string representation.
+ * @param type Type to convert.
+ * @return Type as a string (same as textual representation of the enum in the code).
+ */
+ static const QString typeToString(Type type);
+
+ /**
+ * @brief Provides range of the token in the query.
+ * @return Start and end character index in relation to the query it comes from.
+ */
+ Range getRange();
+
+ /**
+ * @brief Tests whether this token represents any kind of whitespace.
+ * @return true if it's a whitespace, or false otherwise.
+ *
+ * Note, that from SQL perspective also comments are whitespaces.
+ */
+ bool isWhitespace() const;
+
+ /**
+ * @brief Tests whether this token represents separating value (like an operator, or parenthesis) in SQL understanding.
+ * @return true if it's a separating token, or false otherwise.
+ */
+ bool isSeparating() const;
+
+ /**
+ * @brief Tests whether this token is representing any kind of database object name.
+ * @return true if the token is the name an object, or false otherwise.
+ *
+ * From regular token types only the Type::OTHER represents.
+ * For context-oriented types there are several types representing object name.
+ * Use this method to find out which is and which is not.
+ *
+ * You won't need to use this method in most cases. It's useful only to CompletionHelper
+ * for now.
+ */
+ bool isDbObjectType() const;
+
+ /**
+ * @brief Converts token's type into a string representation.
+ * @return Token type as a string.
+ */
+ QString typeString() const;
+
+ /**
+ * @brief Compares other token to this token.
+ * @param other Other token to compare.
+ * @return 1 if tokens are equal, 0 if they're different.
+ *
+ * Tokens are equal then 4 members are equal: type, value, start and end.
+ * The lemonType member is ignored by this operator.
+ */
+ int operator==(const Token& other);
+
+ /**
+ * @brief Compares other token to this token and tells which one is greater.
+ * @param other Other token to compare.
+ * @return true if the other token is greater than this one, or false if it's smaller or equal.
+ *
+ * This operator compares only 2 members: the start and the end indexes. This operator
+ * is used to sort tokens by the character position they occurred at.
+ *
+ * The start value has higher precedence than the end value, but if start values are equal,
+ * then the end value is conclusive.
+ */
+ bool operator<(const Token& other) const;
+
+ /**
+ * @brief Lemon token ID. Used by the Parser class only.
+ */
+ int lemonType;
+
+ /**
+ * @brief Token type, describing general class of the token.
+ */
+ Type type;
+
+ /**
+ * @brief Literal value of the token, captured directly from the query.
+ */
+ QString value = QString::null;
+
+ /**
+ * @brief Start position (first character index) of the token in the query.
+ */
+ qint64 start;
+
+ /**
+ * @brief End position (last character index) of the token in the query.
+ */
+ qint64 end;
+};
+
+/**
+ * @brief qHash implementation for TokenPtr, so it can be used as a key in QHash and QSet.
+ * @param token Token that the hash code is calculated for.
+ * @return Unique integer value for the token.
+ */
+uint qHash(const TokenPtr& token);
+
+struct TolerantToken;
+/**
+ * @brief Shared pointer to TolerantToken.
+ */
+typedef QSharedPointer<TolerantToken> TolerantTokenPtr;
+
+/**
+ * @brief Variation of token that has additional "invalid" flag.
+ *
+ * TolerantToken is used by Lexer to tolerate unfinished comments, like when you start the
+ * comment at the end of the query, but you never close the comment. This is tolerable case,
+ * while not entire correct by the syntax.
+ *
+ * In such cases the syntax highlighter must be aware of the token being invalid, so the proper
+ * state is marked for the paragraph.
+ */
+struct TolerantToken : public Token
+{
+ /**
+ * @brief Invalid state flag for the token.
+ */
+ bool invalid = false;
+};
+
+/**
+ * @brief Ordered list of tokens.
+ *
+ * This is pretty much a QList of Token pointers, but it also provides some
+ * utility methods regarding this collection, which is very common in SQLiteStudio.
+ */
+class API_EXPORT TokenList : public QList<TokenPtr>
+{
+ public:
+ /**
+ * @brief Creates empty list.
+ */
+ TokenList();
+
+ /**
+ * @brief Creates list filled with the same entries as the other list.
+ * @param other List to copy pointers from.
+ */
+ TokenList(const QList<TokenPtr>& other);
+
+ /**
+ * @brief Serializes contents of the list into readable form.
+ * @return Contents in format: <tt>{type1 value1 start1 end1} {type2 value2 start2 end2} ...</tt>.
+ *
+ * Tokens are serialized with Token::toString(), then all serialized values are joined with single whitespace
+ * into the QString.
+ */
+ QString toString() const;
+
+ /**
+ * @brief Serializes tokens from the list into strings.
+ * @return List of tokens serialized into strings.
+ *
+ * Tokens are serialized with Token::toString().
+ */
+ QStringList toStringList() const;
+
+ /**
+ * @brief Provides index of first occurrence of the token in the list.
+ * @param token Token to look for.
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int indexOf(TokenPtr token) const;
+
+ /**
+ * @brief Provides index of first occurrence of the token with given type.
+ * @param type Toke type to look for.
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int indexOf(Token::Type type) const;
+
+ /**
+ * @brief Provides index of first occurrence of the token with given type and value.
+ * @param type Token type to look for.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int indexOf(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Provides index of first occurrence of the token with given value.
+ * @param value Value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int indexOf(const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Provides index of last occurrence of the token in the list.
+ * @param token Token to look for.
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int lastIndexOf(TokenPtr token) const;
+
+ /**
+ * @brief Provides index of last occurrence of the token with given type.
+ * @param type Token type to look for.
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int lastIndexOf(Token::Type type) const;
+
+ /**
+ * @brief Provides index of last occurrence of the token with given type and value.
+ * @param type Token type to look for.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int lastIndexOf(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Provides index of last occurrence of the token with given value.
+ * @param value Value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Index of the token, or -1 if token was not found.
+ */
+ int lastIndexOf(const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Finds first token with given type in the list.
+ * @param type Type to look for.
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr find(Token::Type type) const;
+
+ /**
+ * @brief Finds first token with given type and value.
+ * @param type Type to look for.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr find(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Finds first token with given type and value.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr find(const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Finds last token with given type in the list.
+ * @param type Type to look for.
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr findLast(Token::Type type) const;
+
+ /**
+ * @brief Finds last token with given type and value.
+ * @param type Type to look for.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr findLast(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Finds last token with given value.
+ * @param value Token value to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr findLast(const QString& value, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const;
+
+ /**
+ * @brief Finds token that according to its start and end values covers given character position.
+ * @param cursorPosition Position to get token for.
+ * @return Token found, or null pointer if it was not found.
+ */
+ TokenPtr atCursorPosition(quint64 cursorPosition) const;
+
+ /**
+ * @brief Inserts tokens at given position in this list.
+ * @param i Position to insert at.
+ * @param list List of tokens to insert.
+ */
+ void insert(int i, const TokenList& list);
+
+ /**
+ * @brief Inserts a token at given position in this list.
+ * @param i Position to insert at.
+ * @param token Token to insert.
+ */
+ void insert(int i, TokenPtr token);
+
+ /**
+ * @brief Puts all tokens from the other list to this list.
+ * @param other List to get tokens from.
+ * @return Reference to this list.
+ *
+ * It erases any previous entries in this list, just like you would normally expect for the <tt>=</tt> operator.
+ */
+ TokenList& operator=(const QList<TokenPtr>& other);
+
+ /**
+ * @brief Detokenizes all tokens from this list.
+ * @return String from all tokens.
+ *
+ * This is just a convenient method to call Lexer::detokenize() on this list.
+ */
+ QString detokenize() const;
+
+ /**
+ * @brief Replaces tokens on this list with other tokens.
+ * @param startIdx Position of the first token in this list to replace.
+ * @param length Number of tokens to replace.
+ * @param newTokens New tokens to put in place of removed ones.
+ */
+ void replace(int startIdx, int length, const TokenList& newTokens);
+
+ /**
+ * @brief Replaces tokens on this list with another token.
+ * @param startIdx Position of the first token in this list to replace.
+ * @param length Number of tokens to replace.
+ * @param newToken New token to put in place of removed ones.
+ */
+ void replace(int startIdx, int length, TokenPtr newToken);
+
+ /**
+ * @brief Replaces token with another token.
+ * @param startIdx Position of the token in this list to replace.
+ * @param newToken New token to put in place of removed one.
+ */
+ void replace(int startIdx, TokenPtr newToken);
+
+ /**
+ * @brief Replaces token on this list with other tokens.
+ * @param startIdx Position of the token in this list to replace.
+ * @param newTokens New tokens to put in place of removed ones.
+ */
+ void replace(int startIdx, const TokenList& newTokens);
+
+ /**
+ * @brief Replaces tokens on this list with other tokens.
+ * @param startToken First token to replace.
+ * @param endToken Last token to replace.
+ * @param newTokens New tokens to put in place of removed ones.
+ * @return Number of tokens replaced.
+ *
+ * If either \p startToken or \p endToken were not found on the list, this method does nothing
+ * and returns 0.
+ */
+ int replace(TokenPtr startToken, TokenPtr endToken, const TokenList& newTokens);
+
+ /**
+ * @brief Replaces tokens on this list with other tokens.
+ * @param startToken First token to replace.
+ * @param endToken Last token to replace.
+ * @param newToken New token to put in place of removed ones.
+ * @return Number of tokens replaced.
+ *
+ * If either \p startToken or \p endToken were not found on the list, this method does nothing
+ * and returns 0.
+ */
+ int replace(TokenPtr startToken, TokenPtr endToken, TokenPtr newToken);
+
+ /**
+ * @brief Replaces token on this list with another token.
+ * @param oldToken Token to replace.
+ * @param newToken Token to replace with.
+ * @return true if \p oldToken was found and replaced, or false otherwise.
+ */
+ bool replace(TokenPtr oldToken, TokenPtr newToken);
+
+ /**
+ * @brief Replaces token on this list with other tokens.
+ * @param oldToken Token to replace.
+ * @param newTokens Tokens to replace with.
+ * @return true if \p oldToken was found and replaced, or false otherwise.
+ */
+ bool replace(TokenPtr oldToken, const TokenList& newTokens);
+
+ /**
+ * @brief Removes tokens from the list.
+ * @param startToken First token to remove.
+ * @param endToken Last token to remove.
+ * @return true if \p startToken and \p endToken were found in the list and removed, or false otherwise.
+ *
+ * In case \p startToken is placed after \p endToken, this method does nothing and returns false.
+ */
+ bool remove(TokenPtr startToken, TokenPtr endToken);
+
+ /**
+ * @brief Removes first token of given type from the list.
+ * @param type Token type to remove.
+ * @return true if token was located and removed, or false otherwise.
+ */
+ bool remove(Token::Type type);
+
+ /**
+ * @brief Removes all white-space tokens from the beginning of the list.
+ *
+ * White-space tokens are tested with Token::isWhitespace().
+ */
+ void trimLeft();
+
+ /**
+ * @brief Removes all white-space tokens from the end of the list.
+ *
+ * White-space tokens are tested with Token::isWhitespace().
+ */
+ void trimRight();
+
+ /**
+ * @brief Removes all white-space tokens from both the beginning and the end of the list.
+ *
+ * White-space tokens are tested with Token::isWhitespace().
+ */
+ void trim();
+
+ /**
+ * @brief Removes all tokens that match given criteria from the beginning of the list.
+ * @param type Token type to remove.
+ * @param alsoTrim Token value to remove.
+ *
+ * This method is an extension to the regular trimLeft(). It removes white-space tokens,
+ * as well as tokens that are of given \p type and have given \p value (both conditions must be met).
+ */
+ void trimLeft(Token::Type type, const QString& alsoTrim);
+
+ /**
+ * @brief Removes all tokens that match given criteria from the end of the list.
+ * @param type Token type to remove.
+ * @param alsoTrim Token value to remove.
+ *
+ * This method is an extension to the regular trimRight(). It removes white-space tokens,
+ * as well as tokens that are of given \p type and have given \p value (both conditions must be met).
+ */
+ void trimRight(Token::Type type, const QString& alsoTrim);
+
+ /**
+ * @brief Removes all tokens that match given criteria from the beginning and the end of the list.
+ * @param type Token type to remove.
+ * @param alsoTrim Token value to remove.
+ *
+ * This method is an extension to the regular trim(). It removes white-space tokens,
+ * as well as tokens that are of given \p type and have given \p value (both conditions must be met).
+ */
+ void trim(Token::Type type, const QString& alsoTrim);
+
+ /**
+ * @brief Creates list of tokens from this list, letting through only tokens of given type.
+ * @param type Type of tokens to provide in the new list.
+ * @return List of tokens from this list matching given \p type.
+ */
+ TokenList filter(Token::Type type) const;
+
+ /**
+ * @brief Creates list of tokens from this list, letting through only tokens that are not a whitespace.
+ * @return List of tokens from this list that are not a whitespace.
+ *
+ * The condition to test if tokens is a whitespace is a call to Token::isWhitespace().
+ */
+ TokenList filterWhiteSpaces() const;
+
+ /**
+ * @brief Returns sub-list of tokens from this list.
+ * @param pos Position to start sublist from.
+ * @param length Number of tokens to get from this list. If -1 (default), then all from the \p pos to the end.
+ * @return Sub-list of tokens from this list.
+ */
+ TokenList mid(int pos, int length = -1) const;
+
+ private:
+ /**
+ * @brief Finds first occurrence of token with given type.
+ * @param type Type of token to look for.
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findFirst() and indexOf() methods, as they share common logic.
+ */
+ TokenPtr findFirst(Token::Type type, int* idx) const;
+
+ /**
+ * @brief Finds first occurrence of token with given type and value.
+ * @param type Type of token to look for.
+ * @param value Value of the token to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findFirst() and indexOf() methods, as they share common logic.
+ */
+ TokenPtr findFirst(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const;
+
+ /**
+ * @brief Finds first occurrence of token with given value.
+ * @param value Value of the token to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findFirst() and indexOf() methods, as they share common logic.
+ */
+ TokenPtr findFirst(const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const;
+
+ /**
+ * @brief Finds last occurrence of token with given type.
+ * @param type Type of token to look for.
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findLast() and lastIndexOf() methods, as they share common logic.
+ */
+ TokenPtr findLast(Token::Type type, int* idx) const;
+
+ /**
+ * @brief Finds last occurrence of token with given type and value.
+ * @param type Type of token to look for.
+ * @param value Value of the token to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findLast() and lastIndexOf() methods, as they share common logic.
+ */
+ TokenPtr findLast(Token::Type type, const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const;
+
+ /**
+ * @brief Finds last occurrence of token with given value.
+ * @param value Value of the token to look for.
+ * @param caseSensitivity Should value lookup be case sensitive?
+ * @param idx Pointer to integer variable to store position in.
+ * @return Token found, or null pointer if token was not found.
+ *
+ * If \p idx is not null, then the position of token found is stored in it. If token was not found,
+ * then -1 is stored in the \p idx.
+ *
+ * This method is used by the public findLast() and lastIndexOf() methods, as they share common logic.
+ */
+ TokenPtr findLast(const QString& value, Qt::CaseSensitivity caseSensitivity, int* idx) const;
+};
+
+
+#endif // TOKEN_H