From f815247510a1c332669ec27ac8364be99b9da2fc Mon Sep 17 00:00:00 2001 From: Pedro Flemming Date: Mon, 14 Aug 2017 15:13:56 +0200 Subject: [PATCH] Add documentation about missing features (#56) --- docs/README.md | 3 +- docs/known-limitations.md | 18 +++ docs/syntax-examples.md | 44 ------- docs/syntax-support.md | 53 +++++++++ src/sql/Expr.h | 3 - test/auto_query_file_test.cpp | 98 ++++++++++++++++ test/queries/queries-bad.sql | 11 ++ .../queries-good.sql} | 13 +-- test/sql_grammar_test.cpp | 107 ------------------ test/test.sh | 5 +- 10 files changed, 188 insertions(+), 167 deletions(-) create mode 100644 docs/known-limitations.md delete mode 100644 docs/syntax-examples.md create mode 100644 docs/syntax-support.md create mode 100644 test/auto_query_file_test.cpp create mode 100644 test/queries/queries-bad.sql rename test/{valid_queries.sql => queries/queries-good.sql} (90%) delete mode 100644 test/sql_grammar_test.cpp diff --git a/docs/README.md b/docs/README.md index f519412..f80ee5a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,8 @@ Documentation Internal Links: * [Developer Documentation](dev-docs.md) - * [Working SQL Syntax Examples](syntax-examples.md) + * [Supported SQL Queries](syntax-support.md) + * [Known Limitations & Missing Features](known-limitations.md) External Resources: diff --git a/docs/known-limitations.md b/docs/known-limitations.md new file mode 100644 index 0000000..0c91b04 --- /dev/null +++ b/docs/known-limitations.md @@ -0,0 +1,18 @@ +Known Limitations & Missing Features +==================================== + +This page contains an overview of known missing limitations and missing features in our SQL parser project. In general, we would like to see all of these features being supported at some point. If you are particularly interested in a specific feature, feel free to contribute to this project through a pull request. + +### Completely Missing Statement Types + + * EXPLAIN + * EXPORT + * RENAME + * ALTER + +Additionally, there are a lot of statement types that are specific to certain database systems. Supporting all of these is not on our roadmap, but if someone implements support for such a statement, we can also integrate it. + +### Other SQL Limitations + + * Tables names ignore the schema name (see grammar rule `table_name`). This affects, for example, `INSERT, IMPORT, DROP, DELETE`. + * Column data types only support `INT, DOUBLE, TEXT`. diff --git a/docs/syntax-examples.md b/docs/syntax-examples.md deleted file mode 100644 index be1d4d0..0000000 --- a/docs/syntax-examples.md +++ /dev/null @@ -1,44 +0,0 @@ -Syntax Examples -=============== - -This page contains some samples of SQL statements that can be executed in Hyrise. - - -**Create Tables** -```sql -CREATE TABLE IF NOT EXISTS students FROM TBL FILE 'test/students.tbl'; -CREATE TABLE test (v1 INTEGER, v2 INTEGER, v3 INTEGER); -``` - - -**Select with Join** -```sql -SELECT name, city, * FROM students AS t1 JOIN students AS t2 ON t1.city = t2.city WHERE t1.grade < 2.0 AND t2.grade > 2.0 AND t1.city = 'Frohnau' ORDER BY t1.grade DESC; -``` - - -**Group By** -```sql -SELECT city, AVG(grade) AS average, MIN(grade) AS best, MAX(grade) AS worst FROM students GROUP BY city; -``` - - -**Update and Delete** -```sql -UPDATE students SET name='Max Mustermann' WHERE name = 'Ralf Stiebitz'; -DELETE FROM students WHERE name = 'Max Mustermann'; -``` - - -**Prepare and Execute** -```sql -PREPARE batch_insert { - INSERT INTO test VALUES (?, 0, 0); - INSERT INTO test VALUES (?, 0, 0); - INSERT INTO test VALUES (?, 0, 0); - INSERT INTO test VALUES (?, 0, 0); - INSERT INTO test VALUES (?, 0, 0); -}; - -EXECUTE insert_test(1, 2, 3, 4 ,5); -``` diff --git a/docs/syntax-support.md b/docs/syntax-support.md new file mode 100644 index 0000000..59d08b9 --- /dev/null +++ b/docs/syntax-support.md @@ -0,0 +1,53 @@ +Supported SQL Queries +===================== + +This page contains a short list of queries that can be correctly parsed with our parser. If you are interested in finding out if a certain feature is supported, it is probably the easiest to checkout the repository and try the example project or check our [list of known limitations](known-limitations.md). Also the file [queries-good.sql](../test/queries/queries-good.sql) shows a list of queries which are parsable with the current version. + + +## Select Statements + +We implement a broad support for the most common elements for `SELECT` statements. Following are a few examples of basic constructs that are supported. + +```sql +SELECT name, city, * + FROM students AS t1 JOIN students AS t2 ON t1.city = t2.city + WHERE t1.grade < 2.0 AND + t2.grade > 2.0 AND + t1.city = 'Frohnau' + ORDER BY t1.grade DESC; + +SELECT city, AVG(grade) AS average, + MIN(grade) AS best, MAX(grade) AS worst + FROM students + GROUP BY city; +``` + +## Data Definition & Modification + +**Create Tables** +```sql +CREATE TABLE students ( + name TEXT, + student_number INTEGER, + city TEXT, + grade DOUBLE +); +``` + +**Update and Delete** +```sql +UPDATE students SET name='Max Mustermann' WHERE name = 'Ralf Mustermann'; + +DELETE FROM students WHERE name = 'Max Mustermann'; +``` + + +## Prepared Statements + +The definition and execution of prepared statements is supported using the following syntax. + +```sql +PREPARE select_test FROM 'SELECT * FROM customer WHERE c_name = ?;'; + +EXECUTE select_test('Max Mustermann'); +``` diff --git a/src/sql/Expr.h b/src/sql/Expr.h index 622bec3..dcaddee 100644 --- a/src/sql/Expr.h +++ b/src/sql/Expr.h @@ -29,9 +29,6 @@ namespace hsql { }; // Operator types. These are important for expressions of type kExprOperator. -// Trivial types are those that can be described by a single character e.g: -// + - * / < > = % -// Non-trivial are: <> <= >= LIKE ISNULL NOT enum OperatorType { kOpNone, diff --git a/test/auto_query_file_test.cpp b/test/auto_query_file_test.cpp new file mode 100644 index 0000000..ce18300 --- /dev/null +++ b/test/auto_query_file_test.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include + +#include "thirdparty/microtest/microtest.h" +#include "SQLParser.h" + +// Read all lines from the given file path. Skips comment lines. +std::vector readlines(std::string path); + +// Read the queries from all files that were supplied to the test +// through the -f argument. For all queries it is checked whether they +// can be parsed successfully. +TEST(AutoQueryFileTest) { + const std::vector& args = mt::Runtime::args(); + + std::vector query_files; + + // Parse command line arguments to retrieve query files. + uint i = 1; + for (; i < args.size(); ++i) { + if (args[i] == "-f") { + query_files.push_back(args[++i]); + } + } + + + // Read list of queries from all input files. + std::vector lines; + for (std::string path : query_files) { + std::vector tmp = readlines(path); + lines.insert(lines.end(), tmp.begin(), tmp.end()); + } + + // Execute queries. + size_t num_executed = 0; + size_t num_failed = 0; + for (std::string line : lines) { + bool expected_result = true; + std::string query = line; + + // If a line starts with '!' parsing is expected to fail. + if (query.at(0) == '!') { + expected_result = false; + query = query.substr(1); + } + + // Measuring the parsing time. + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); + + // Parse the query. + hsql::SQLParserResult result; + hsql::SQLParser::parse(query, &result); + + end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + double us = elapsed_seconds.count() * 1000 * 1000; + + if (expected_result == result.isValid()) { + printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, line.c_str()); + } else { + printf("\033[0;31m{ failed}\033[0m\n"); + printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result.errorMsg(), result.errorLine(), result.errorColumn()); + printf("\t%s\n", line.c_str()); + ++num_failed; + } + ++num_executed; + } + + if (num_failed == 0) { + printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", num_executed); + } else { + fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %lu out of %lu tests failed!\n", num_failed, num_executed); + } + ASSERT_EQ(num_failed, 0); +} + +std::vector readlines(std::string path) { + std::ifstream infile(path); + std::vector lines; + std::string line; + while (std::getline(infile, line)) { + std::istringstream iss(line); + + // Skip comments. + if (line[0] == '#' || + (line[0] == '-' && line[1] == '-')) { + continue; + } + + lines.push_back(line); + } + return lines; +} diff --git a/test/queries/queries-bad.sql b/test/queries/queries-bad.sql new file mode 100644 index 0000000..f67c7c8 --- /dev/null +++ b/test/queries/queries-bad.sql @@ -0,0 +1,11 @@ +# This file contains a list of strings that are NOT valid SQL queries. +# Each line contains a single SQL query. +# Each line starts with a '!' char to indicate that parsing should fail. +! +!1 +!gibberish; +!SELECT abc; +!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1 +!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1 +!INSERT INTO test_table VALUESd (1, 2, 'test'); +!SELECT * FROM t WHERE a = ? AND b = ?;SELECT 1; \ No newline at end of file diff --git a/test/valid_queries.sql b/test/queries/queries-good.sql similarity index 90% rename from test/valid_queries.sql rename to test/queries/queries-good.sql index ef08be0..294aa63 100644 --- a/test/valid_queries.sql +++ b/test/queries/queries-good.sql @@ -1,3 +1,5 @@ +# This file contains a list of strings that are NOT valid SQL queries. +# Each line contains a single SQL query. # SELECT statement SELECT * FROM orders; SELECT a FROM foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10 @@ -46,13 +48,4 @@ DEALLOCATE PREPARE prep; # HINTS SELECT * FROM test WITH HINT(NO_CACHE); SELECT * FROM test WITH HINT(NO_CACHE, NO_SAMPLING); -SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test')); -# Error expeced -! -!1 -!gibberish; -!SELECT abc; -!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1 -!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1 -!INSERT INTO test_table VALUESd (1, 2, 'test'); -!SELECT * FROM t WHERE a = ? AND b = ?;SELECT 1; \ No newline at end of file +SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test')); \ No newline at end of file diff --git a/test/sql_grammar_test.cpp b/test/sql_grammar_test.cpp deleted file mode 100644 index 8429a43..0000000 --- a/test/sql_grammar_test.cpp +++ /dev/null @@ -1,107 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include "thirdparty/microtest/microtest.h" -#include "SQLParser.h" - -using namespace hsql; - - -std::vector readlines(std::string path) { - std::ifstream infile(path); - std::vector lines; - std::string line; - while (std::getline(infile, line)) { - std::istringstream iss(line); - - // Skip comments - if (line[0] == '#' || - (line[0] == '-' && line[1] == '-')) { - continue; - } - - lines.push_back(line); - } - return lines; -} - -#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0) - -TEST(AutoGrammarTest) { - const std::vector& args = mt::Runtime::args(); - if (args.size() <= 1) { - fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n"); - return; - } - - bool globalExpectFalse = false; - bool useFile = false; - std::string filePath = ""; - - // Parse command line arguments - uint i = 1; - for (; i < args.size(); ++i) { - if (STREQ(args[i], "--false")) globalExpectFalse = true; - else if (STREQ(args[i], "-f")) { - useFile = true; - filePath = args[++i]; - } else { - break; - } - } - - - // Read list of queries for this rest - std::vector queries; - if (useFile) { - queries = readlines(filePath); - } else { - for (; i < args.size(); ++i) queries.push_back(args[i]); - } - - - // Execute queries - int numFailed = 0; - for (std::string sql : queries) { - bool expectFalse = globalExpectFalse; - if (sql.at(0) == '!') { - expectFalse = !expectFalse; - sql = sql.substr(1); - } - - // Measuring the parsing time - std::chrono::time_point start, end; - start = std::chrono::system_clock::now(); - - // Parsing - SQLParserResult result; - SQLParser::parse(sql.c_str(), &result); - - end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - double us = elapsed_seconds.count() * 1000 * 1000; - - if (expectFalse == result.isValid()) { - printf("\033[0;31m{ failed}\033[0m\n"); - printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result.errorMsg(), result.errorLine(), result.errorColumn()); - printf("\t%s\n", sql.c_str()); - numFailed++; - } else { - // TODO: indicate whether expectFalse was set - printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str()); - } - } - - if (numFailed == 0) { - printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size()); - } else { - fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size()); - } - ASSERT_EQ(numFailed, 0); -} - diff --git a/test/test.sh b/test/test.sh index 06cd93f..5766a13 100755 --- a/test/test.sh +++ b/test/test.sh @@ -17,7 +17,7 @@ CONFLICT_RET=0 ################################################# # Running SQL parser tests. printf "\n${GREEN}Running SQL parser tests...${NC}\n" -bin/tests -f "test/valid_queries.sql" +bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql" SQL_TEST_RET=$? if [ $SQL_TEST_RET -eq 0 ]; then @@ -31,7 +31,8 @@ fi # Running memory leak checks. printf "\n${GREEN}Running memory leak checks...${NC}\n" valgrind --leak-check=full --error-exitcode=200 --log-fd=3 \ - ./bin/tests -f "test/valid_queries.sql" 3>&1 >/dev/null 2>/dev/null + bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql" \ + 3>&1 >/dev/null 2>/dev/null MEM_LEAK_RET=$? if [ $MEM_LEAK_RET -ne 200 ]; then