Add documentation about missing features (#56)

This commit is contained in:
Pedro Flemming 2017-08-14 15:13:56 +02:00 committed by GitHub
parent 88ffe4822b
commit f815247510
10 changed files with 188 additions and 167 deletions

View File

@ -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:

18
docs/known-limitations.md Normal file
View File

@ -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`.

View File

@ -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);
```

53
docs/syntax-support.md Normal file
View File

@ -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');
```

View File

@ -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,

View File

@ -0,0 +1,98 @@
#include <stdio.h>
#include <string>
#include <chrono>
#include <fstream>
#include <sstream>
#include <vector>
#include "thirdparty/microtest/microtest.h"
#include "SQLParser.h"
// Read all lines from the given file path. Skips comment lines.
std::vector<std::string> 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<std::string>& args = mt::Runtime::args();
std::vector<std::string> 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<std::string> lines;
for (std::string path : query_files) {
std::vector<std::string> 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<std::chrono::system_clock> 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<double> 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<std::string> readlines(std::string path) {
std::ifstream infile(path);
std::vector<std::string> 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;
}

View File

@ -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;

View File

@ -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
@ -47,12 +49,3 @@ DEALLOCATE PREPARE prep;
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;

View File

@ -1,107 +0,0 @@
#include <stdio.h>
#include <string>
#include <chrono>
#include <fstream>
#include <sstream>
#include <vector>
#include "thirdparty/microtest/microtest.h"
#include "SQLParser.h"
using namespace hsql;
std::vector<std::string> readlines(std::string path) {
std::ifstream infile(path);
std::vector<std::string> 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<std::string>& 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<std::string> 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<std::chrono::system_clock> 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<double> 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);
}

View File

@ -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