diff options
| author | 2021-12-17 07:06:30 -0500 | |
|---|---|---|
| committer | 2021-12-17 07:06:30 -0500 | |
| commit | 1fdc150116cad39aae5c5da407c3312b47a59e3a (patch) | |
| tree | 123c79a4d7ad2d45781ba03ce939f7539fb428d8 /SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp | |
| parent | feda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 (diff) | |
New upstream version 3.3.3+dfsg1.upstream/3.3.3+dfsg1
Diffstat (limited to 'SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp')
| -rw-r--r-- | SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp | 198 |
1 files changed, 186 insertions, 12 deletions
diff --git a/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp b/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp index eb2a76f..6d537dc 100644 --- a/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp +++ b/SQLiteStudio3/Tests/ParserTest/tst_parsertest.cpp @@ -8,6 +8,9 @@ #include "parser/lexer.h" #include "parser/parsererror.h" #include "common/utils_sql.h" +#include "parser/ast/sqlitewindowdefinition.h" +#include "parser/ast/sqlitefilterover.h" +#include "common/compatibility.h" #include <QString> #include <QtTest> @@ -19,11 +22,15 @@ class ParserTest : public QObject ParserTest(); private: - Parser* parser2 = nullptr; Parser* parser3 = nullptr; + void verifyWindowClause(const QString& sql, SqliteSelectPtr& select, bool& ok); private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void test(); + void testString(); void testScientificNumber(); void testUniqConflict(); void testGetTableTokens(); @@ -49,8 +56,11 @@ class ParserTest : public QObject void testRebuildTokensUpdate(); void testRebuildTokensInsertUpsert(); void testGetColumnTokensFromInsertUpsert(); - void initTestCase(); - void cleanupTestCase(); + void testGeneratedColumn(); + void testWindowClause(); + void testFilterClause(); + void testUpdateFrom(); + void testStringAsTableId(); }; ParserTest::ParserTest() @@ -82,10 +92,26 @@ void ParserTest::test() TokenList tokens = query->getContextTableTokens(); } +void ParserTest::testString() +{ + QString sql = "SELECT 1 = '1';"; + + parser3->parse(sql); + QCOMPARE(parser3->getErrors().size(), 0); + + SqliteQueryPtr query = parser3->getQueries()[0]; + query->rebuildTokens(); + + QCOMPARE(query->tokens.detokenize(), sql); + QCOMPARE(query->tokens.size(), 8); + QCOMPARE(query->tokens[2]->type, Token::Type::INTEGER); + QCOMPARE(query->tokens[6]->type, Token::Type::STRING); +} + void ParserTest::testScientificNumber() { QString sql = "SELECT 1e100;"; - TokenList tokens = Lexer::tokenize(sql, Dialect::Sqlite3); + TokenList tokens = Lexer::tokenize(sql); QVERIFY(tokens.size() == 4); QVERIFY(tokens[2]->type == Token::Type::FLOAT); @@ -96,7 +122,7 @@ void ParserTest::testGetTableTokens() QString sql = "select someTable.* FROM someTable;"; parser3->parse(sql); - QVERIFY(parser3->getErrors().size() == 0); + QCOMPARE(parser3->getErrors().size(), 0); SqliteQueryPtr query = parser3->getQueries()[0]; TokenList tokens = query->getContextTableTokens(); @@ -110,7 +136,7 @@ void ParserTest::testGetTableTokens2() QString sql = "select db.tab.col FROM someTable;"; parser3->parse(sql); - QVERIFY(parser3->getErrors().size() == 0); + QCOMPARE(parser3->getErrors().size(), 0); SqliteQueryPtr query = parser3->getQueries()[0]; TokenList tokens = query->getContextTableTokens(); @@ -228,7 +254,7 @@ void ParserTest::testCommentEnding2() void ParserTest::testOper1() { QString sql = "SELECT dfgd<=2"; - TokenList tokens = Lexer::tokenize(sql, Dialect::Sqlite3); + TokenList tokens = Lexer::tokenize(sql); QVERIFY(tokens[2]->value == "dfgd"); QVERIFY(tokens[3]->value == "<="); QVERIFY(tokens[4]->value == "2"); @@ -381,7 +407,7 @@ void ParserTest::testExpr() void ParserTest::testCommentBeginMultiline() { QString sql = "/*"; - TokenList tokens = Lexer::tokenize(sql, Dialect::Sqlite3); + TokenList tokens = Lexer::tokenize(sql); QVERIFY(tokens.size() == 1); QVERIFY(tokens[0]->type == Token::COMMENT); } @@ -494,22 +520,170 @@ void ParserTest::testGetColumnTokensFromInsertUpsert() QVERIFY(insert->upsert); TokenList tk = insert->getContextColumnTokens(); - qSort(tk.begin(), tk.end(), [](const TokenPtr& t1, const TokenPtr& t2) {return t1->start < t2->start;}); + sSort(tk, [](const TokenPtr& t1, const TokenPtr& t2) {return t1->start < t2->start;}); QVERIFY(tk.toValueList().join(" ") == "a1 a2 b1 b2 b3 col1 col2 col3 x"); } +void ParserTest::testGeneratedColumn() +{ + QString sql = "create table t2 (a INTEGER PRIMARY KEY AUTOINCREMENT, b INTEGER GENERATED ALWAYS AS (a+2) STORED);"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteCreateTablePtr create = parser3->getQueries().first().dynamicCast<SqliteCreateTable>(); + QVERIFY(create->columns.size() == 2); + QVERIFY(create->columns[1]->constraints.size() == 1); + QVERIFY(create->columns[1]->constraints[0]->type == SqliteCreateTable::Column::Constraint::GENERATED); + QVERIFY(create->columns[1]->constraints[0]->generatedKw == true); + QVERIFY(create->columns[1]->constraints[0]->generatedType == SqliteCreateTable::Column::Constraint::GeneratedType::STORED); + QVERIFY(create->columns[1]->constraints[0]->expr); +} + +void ParserTest::testWindowClause() +{ + QString sql = "SELECT x, y, row_number() OVER win1, rank() OVER win2 " + " FROM t0 " + "WINDOW win1 AS (ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)," + " win2 AS (PARTITION BY y ORDER BY x)" + " ORDER BY x;"; + + SqliteSelectPtr select; + bool ok = false; + verifyWindowClause(sql, select, ok); + if (!ok) + return; + + qInfo() << "first run PASS, runing second time, after detokenizing"; + sql = select->detokenize(); + verifyWindowClause(sql, select, ok); +} + +void ParserTest::verifyWindowClause(const QString& sql, SqliteSelectPtr& select, bool& ok) +{ + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + select = parser3->getQueries().first().dynamicCast<SqliteSelect>(); + QCOMPARE(select->coreSelects.size(), 1); + SqliteSelect::Core* core = select->coreSelects[0]; + + // Result Columns + QCOMPARE(core->resultColumns.size(), 4); + + QVERIFY(core->resultColumns[0]->expr); + QCOMPARE(core->resultColumns[0]->expr->column, "x"); + + QVERIFY(core->resultColumns[1]->expr); + QCOMPARE(core->resultColumns[1]->expr->column, "y"); + + QVERIFY(core->resultColumns[2]->expr); + QCOMPARE(core->resultColumns[2]->expr->function, "row_number"); + QVERIFY(core->resultColumns[2]->expr->filterOver); + QCOMPARE(core->resultColumns[2]->expr->filterOver->over->name, "win1"); + + QVERIFY(core->resultColumns[3]->expr); + QCOMPARE(core->resultColumns[3]->expr->function, "rank"); + QVERIFY(core->resultColumns[3]->expr->filterOver); + QCOMPARE(core->resultColumns[3]->expr->filterOver->over->name, "win2"); + + // Windows + QCOMPARE(core->windows.size(), 2); + SqliteWindowDefinition* winDef1 = core->windows[0]; + QVERIFY(!winDef1->name.isNull()); + QVERIFY(winDef1->window); + + SqliteWindowDefinition::Window* win1 = winDef1->window; + QVERIFY(win1->mode == SqliteWindowDefinition::Window::Mode::ORDER_BY); + QVERIFY(win1->name.isNull()); + QVERIFY(win1->frame); + QVERIFY(win1->orderBy.size() == 1); + QVERIFY(win1->frame->rangeOrRows == SqliteWindowDefinition::Window::Frame::RangeOrRows::RANGE); + QVERIFY(win1->frame->startBound); + QVERIFY(win1->frame->startBound->type == SqliteWindowDefinition::Window::Frame::Bound::Type::UNBOUNDED_PRECEDING); + QVERIFY(win1->frame->endBound); + QVERIFY(win1->frame->endBound->type == SqliteWindowDefinition::Window::Frame::Bound::Type::CURRENT_ROW); + + SqliteWindowDefinition* winDef2 = core->windows[1]; + QVERIFY(!winDef2->name.isNull()); + QVERIFY(winDef2->window); + + SqliteWindowDefinition::Window* win2 = winDef2->window; + QVERIFY(win2->mode == SqliteWindowDefinition::Window::Mode::PARTITION_BY); + QVERIFY(win2->name.isNull()); + QVERIFY(win2->exprList.size() == 1); + QVERIFY(win2->orderBy.size() == 1); + QVERIFY(!win2->frame); + + ok = true; +} + +void ParserTest::testFilterClause() +{ + QString sql = "SELECT c, a, b, group_concat(b, '.') FILTER (WHERE c!='two') OVER (" + " ORDER BY a" + " ) AS group_concat" + " FROM t1 ORDER BY a;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteSelectPtr select = parser3->getQueries().first().dynamicCast<SqliteSelect>(); + QVERIFY(select->coreSelects.size() == 1); + SqliteSelect::Core* core = select->coreSelects[0]; + QVERIFY(core->windows.size() == 0); + + QVERIFY(core->resultColumns.size() == 4); + SqliteSelect::Core::ResultColumn* resCol = core->resultColumns[3]; + QVERIFY(resCol->alias == "group_concat"); + QVERIFY(resCol->expr); + QVERIFY(resCol->expr->filterOver); + QVERIFY(resCol->expr->filterOver->filter->expr); + QVERIFY(resCol->expr->filterOver->over); + QVERIFY(resCol->expr->filterOver->over->mode == SqliteFilterOver::Over::Mode::WINDOW); + QVERIFY(resCol->expr->filterOver->over->window); + QVERIFY(resCol->expr->filterOver->over->window->mode == SqliteWindowDefinition::Window::Mode::ORDER_BY); +} + +void ParserTest::testUpdateFrom() +{ + QString sql = "UPDATE inventory" + " SET quantity = quantity - daily.amt" + " FROM (SELECT sum(quantity) AS amt, itemId FROM sales GROUP BY 2) AS daily" + " WHERE inventory.itemId = daily.itemId;"; + + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); + + SqliteUpdatePtr update = parser3->getQueries().first().dynamicCast<SqliteUpdate>(); + QVERIFY(update->where); + QCOMPARE(update->keyValueMap.size(), 1); + QVERIFY(update->from); + QVERIFY(update->from->singleSource); + QVERIFY(update->from->singleSource->select); + QCOMPARE(update->from->singleSource->alias, "daily"); +} + +void ParserTest::testStringAsTableId() +{ + QString sql = "select 'bb'.id1 = 'bb'.id2;"; + bool res = parser3->parse(sql); + QVERIFY(res); + QVERIFY(parser3->getErrors().isEmpty()); +} + void ParserTest::initTestCase() { initKeywords(); Lexer::staticInit(); initUtilsSql(); - parser2 = new Parser(Dialect::Sqlite2); - parser3 = new Parser(Dialect::Sqlite3); + parser3 = new Parser(); } void ParserTest::cleanupTestCase() { - delete parser2; delete parser3; } |
