diff options
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser')
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 |
