Merge branch 'master' into print-op-expr

This commit is contained in:
mrks 2017-10-24 15:20:53 +02:00 committed by GitHub
commit 4d36a1d426
32 changed files with 1965 additions and 2267 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ cmake-build-debug/
*.swp
*.csv
# macOS compilation dirs
*.dSYM

View File

@ -4,10 +4,10 @@ language: cpp
install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get -qq update
- sudo apt-get install -y g++-4.8 libstdc++-4.8-dev
- sudo apt-get install -y flex valgrind
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
- sudo apt-get install -y g++-6 libstdc++-6-dev
- sudo apt-get install -y valgrind
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 90
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 90
# Install bison 3.0.4.
- wget http://ftp.gnu.org/gnu/bison/bison-3.0.4.tar.gz
@ -16,21 +16,34 @@ install:
- ./configure && make && sudo make install
- cd ..
# Install flex 2.6.4
- wget https://github.com/westes/flex/releases/download/v2.6.4/flex-2.6.4.tar.gz
- tar -xvzf flex-2.6.4.tar.gz
- cd flex-2.6.4
- ./configure && make && sudo make install
- cd ..
# Show installed versions.
- which g++
- g++ -v
- bison --version
- flex --version
- valgrind --version
- if [ "$CXX" = "clang++" ]; then export CXXFLAGS="-stdlib=libc++"; fi
compiler:
- gcc
- clang
script:
# bi build with flex/bison files checked into repo
- make -j4
- make test
- make test_example
# build flex/bison files in CI
- make cleanall
- make -j4
- make test
- make test_example

View File

@ -36,17 +36,17 @@ GMAKE = make mode=$(mode)
NAME := sqlparser
PARSER_CPP = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
PARSER_H = $(SRCPARSER)/bison_parser.h $(SRCPARSER)/flex_lexer.h
LIB_CFLAGS = -std=c++1z -Wall -Werror $(OPT_FLAG)
static ?= no
ifeq ($(static), yes)
LIB_BUILD = lib$(NAME).a
LIBLINKER = $(AR)
LIB_CFLAGS = -std=c++11 -Wall -Werror $(OPT_FLAG)
LIB_LFLAGS = rs
else
LIB_BUILD = lib$(NAME).so
LIBLINKER = $(CXX)
LIB_CFLAGS = -std=c++11 -Wall -Werror -fPIC $(OPT_FLAG)
LIB_CFLAGS += -fPIC
LIB_LFLAGS = -shared -o
endif
LIB_CPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(PARSER_CPP)
@ -60,7 +60,7 @@ $(LIB_BUILD): $(LIB_OBJ)
$(LIBLINKER) $(LIB_LFLAGS) $(LIB_BUILD) $(LIB_OBJ)
$(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp $(SRCPARSER)/bison_parser.cpp
$(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration -Wno-deprecated-register
$(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration
%.o: %.cpp $(PARSER_CPP) $(LIB_H)
$(CXX) $(LIB_CFLAGS) -c -o $@ $<
@ -120,7 +120,7 @@ $(BM_BUILD): $(BM_ALL) $(LIB_BUILD)
############ Test & Example ############
########################################
TEST_BUILD = $(BIN)/tests
TEST_CFLAGS = -std=c++11 -Wall -Werror -Isrc/ -Itest/ -L./ $(OPT_FLAG)
TEST_CFLAGS = -std=c++1z -Wall -Werror -Isrc/ -Itest/ -L./ $(OPT_FLAG)
TEST_CPP = $(shell find test/ -name '*.cpp')
TEST_ALL = $(shell find test/ -name '*.cpp') $(shell find test/ -name '*.h')
EXAMPLE_SRC = $(shell find example/ -name '*.cpp') $(shell find example/ -name '*.h')

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

@ -1,5 +1,5 @@
CFLAGS = -std=c++11 -lstdc++ -Wall -Werror -I../src/ -L../
CFLAGS = -std=c++1z -lstdc++ -Wall -Werror -I../src/ -L../
all:
$(CXX) $(CFLAGS) example.cpp -o example -lsqlparser

File diff suppressed because it is too large Load Diff

View File

@ -235,7 +235,9 @@ union HSQL_STYPE
hsql::DropStatement* drop_stmt;
hsql::PrepareStatement* prep_stmt;
hsql::ExecuteStatement* exec_stmt;
hsql::ShowStatement* show_stmt;
hsql::TableName table_name;
hsql::TableRef* table;
hsql::Expr* expr;
hsql::OrderDescription* order;
@ -254,7 +256,7 @@ union HSQL_STYPE
std::vector<hsql::Expr*>* expr_vec;
std::vector<hsql::OrderDescription*>* order_vec;
#line 258 "bison_parser.h" /* yacc.c:1909 */
#line 260 "bison_parser.h" /* yacc.c:1909 */
};
typedef union HSQL_STYPE HSQL_STYPE;

83
src/parser/bison_parser.y Normal file → Executable file
View File

@ -107,7 +107,9 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
hsql::DropStatement* drop_stmt;
hsql::PrepareStatement* prep_stmt;
hsql::ExecuteStatement* exec_stmt;
hsql::ShowStatement* show_stmt;
hsql::TableName table_name;
hsql::TableRef* table;
hsql::Expr* expr;
hsql::OrderDescription* order;
@ -132,6 +134,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
** Descrutor symbols
*********************************/
%destructor { } <fval> <ival> <uval> <bval> <order_type>
%destructor { free( ($$.name) ); free( ($$.schema) ); } <table_name>
%destructor { free( ($$) ); } <sval>
%destructor {
if (($$) != nullptr) {
@ -182,8 +185,10 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <delete_stmt> delete_statement truncate_statement
%type <update_stmt> update_statement
%type <drop_stmt> drop_statement
%type <sval> table_name opt_alias alias file_path prepare_target_query
%type <bval> opt_not_exists opt_distinct
%type <show_stmt> show_statement
%type <table_name> table_name
%type <sval> opt_alias alias file_path prepare_target_query
%type <bval> opt_not_exists opt_exists opt_distinct
%type <uval> import_file_type opt_join_type column_type
%type <table> from_clause table_ref table_ref_atomic table_ref_name nonjoin_table_ref_atomic
%type <table> join_clause table_ref_name_no_alias
@ -271,6 +276,9 @@ statement:
$$ = $1;
$$->hints = $2;
}
| show_statement {
$$ = $1;
}
;
@ -348,7 +356,8 @@ import_statement:
IMPORT FROM import_file_type FILE file_path INTO table_name {
$$ = new ImportStatement((ImportType) $3);
$$->filePath = $5;
$$->tableName = $7;
$$->schema = $7.schema;
$$->tableName = $7.name;
}
;
@ -361,6 +370,23 @@ file_path:
;
/******************************
* Show Statement
* SHOW TABLES;
******************************/
show_statement:
SHOW TABLES {
$$ = new ShowStatement(kShowTables);
}
| SHOW COLUMNS table_name {
$$ = new ShowStatement(kShowColumns);
$$->schema = $3.schema;
$$->name = $3.name;
}
;
/******************************
* Create Statement
* CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)
@ -370,19 +396,22 @@ create_statement:
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
$$ = new CreateStatement(kCreateTableFromTbl);
$$->ifNotExists = $3;
$$->tableName = $4;
$$->schema = $4.schema;
$$->tableName = $4.name;
$$->filePath = $8;
}
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
$$ = new CreateStatement(kCreateTable);
$$->ifNotExists = $3;
$$->tableName = $4;
$$->schema = $4.schema;
$$->tableName = $4.name;
$$->columns = $6;
}
| CREATE VIEW opt_not_exists table_name opt_column_list AS select_statement {
$$ = new CreateStatement(kCreateView);
$$->ifNotExists = $3;
$$->tableName = $4;
$$->schema = $4.schema;
$$->tableName = $4.name;
$$->viewColumns = $5;
$$->select = $7;
}
@ -419,20 +448,30 @@ column_type:
******************************/
drop_statement:
DROP TABLE table_name {
DROP TABLE opt_exists table_name {
$$ = new DropStatement(kDropTable);
$$->name = $3;
$$->ifExists = $3;
$$->schema = $4.schema;
$$->name = $4.name;
}
| DROP VIEW table_name {
| DROP VIEW opt_exists table_name {
$$ = new DropStatement(kDropView);
$$->name = $3;
$$->ifExists = $3;
$$->schema = $4.schema;
$$->name = $4.name;
}
| DEALLOCATE PREPARE IDENTIFIER {
$$ = new DropStatement(kDropPreparedStatement);
$$->ifExists = false;
$$->name = $3;
}
;
opt_exists:
IF EXISTS { $$ = true; }
| /* empty */ { $$ = false; }
;
/******************************
* Delete Statement / Truncate statement
* DELETE FROM students WHERE grade > 3.0
@ -441,7 +480,8 @@ drop_statement:
delete_statement:
DELETE FROM table_name opt_where {
$$ = new DeleteStatement();
$$->tableName = $3;
$$->schema = $3.schema;
$$->tableName = $3.name;
$$->expr = $4;
}
;
@ -449,7 +489,8 @@ delete_statement:
truncate_statement:
TRUNCATE table_name {
$$ = new DeleteStatement();
$$->tableName = $2;
$$->schema = $2.schema;
$$->tableName = $2.name;
}
;
@ -461,13 +502,15 @@ truncate_statement:
insert_statement:
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
$$ = new InsertStatement(kInsertValues);
$$->tableName = $3;
$$->schema = $3.schema;
$$->tableName = $3.name;
$$->columns = $4;
$$->values = $7;
}
| INSERT INTO table_name opt_column_list select_no_paren {
$$ = new InsertStatement(kInsertSelect);
$$->tableName = $3;
$$->schema = $3.schema;
$$->tableName = $3.name;
$$->columns = $4;
$$->select = $5;
}
@ -500,7 +543,7 @@ update_clause_commalist:
;
update_clause:
IDENTIFIER '=' literal {
IDENTIFIER '=' expr {
$$ = new UpdateClause();
$$->column = $1;
$$->value = $3;
@ -855,7 +898,8 @@ table_ref_commalist:
table_ref_name:
table_name opt_alias {
auto tbl = new TableRef(kTableName);
tbl->name = $1;
tbl->schema = $1.schema;
tbl->name = $1.name;
tbl->alias = $2;
$$ = tbl;
}
@ -865,14 +909,15 @@ table_ref_name:
table_ref_name_no_alias:
table_name {
$$ = new TableRef(kTableName);
$$->name = $1;
$$->schema = $1.schema;
$$->name = $1.name;
}
;
table_name:
IDENTIFIER
| IDENTIFIER '.' IDENTIFIER { $$ = $3; }
IDENTIFIER { $$.schema = nullptr; $$.name = $1;}
| IDENTIFIER '.' IDENTIFIER { $$.schema = $1; $$.name = $3; }
;

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
#define hsql_HEADER_H 1
#define hsql_IN_HEADER 1
#line 5 "flex_lexer.h"
#line 6 "flex_lexer.h"
#line 7 "flex_lexer.h"
#line 8 "flex_lexer.h"
#define YY_INT_ALIGNED short int
@ -13,245 +13,11 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 4
#define YY_FLEX_SUBMINOR_VERSION 1
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
#ifdef yy_create_buffer
#define hsql__create_buffer_ALREADY_DEFINED
#else
#define yy_create_buffer hsql__create_buffer
#endif
#ifdef yy_delete_buffer
#define hsql__delete_buffer_ALREADY_DEFINED
#else
#define yy_delete_buffer hsql__delete_buffer
#endif
#ifdef yy_scan_buffer
#define hsql__scan_buffer_ALREADY_DEFINED
#else
#define yy_scan_buffer hsql__scan_buffer
#endif
#ifdef yy_scan_string
#define hsql__scan_string_ALREADY_DEFINED
#else
#define yy_scan_string hsql__scan_string
#endif
#ifdef yy_scan_bytes
#define hsql__scan_bytes_ALREADY_DEFINED
#else
#define yy_scan_bytes hsql__scan_bytes
#endif
#ifdef yy_init_buffer
#define hsql__init_buffer_ALREADY_DEFINED
#else
#define yy_init_buffer hsql__init_buffer
#endif
#ifdef yy_flush_buffer
#define hsql__flush_buffer_ALREADY_DEFINED
#else
#define yy_flush_buffer hsql__flush_buffer
#endif
#ifdef yy_load_buffer_state
#define hsql__load_buffer_state_ALREADY_DEFINED
#else
#define yy_load_buffer_state hsql__load_buffer_state
#endif
#ifdef yy_switch_to_buffer
#define hsql__switch_to_buffer_ALREADY_DEFINED
#else
#define yy_switch_to_buffer hsql__switch_to_buffer
#endif
#ifdef yypush_buffer_state
#define hsql_push_buffer_state_ALREADY_DEFINED
#else
#define yypush_buffer_state hsql_push_buffer_state
#endif
#ifdef yypop_buffer_state
#define hsql_pop_buffer_state_ALREADY_DEFINED
#else
#define yypop_buffer_state hsql_pop_buffer_state
#endif
#ifdef yyensure_buffer_stack
#define hsql_ensure_buffer_stack_ALREADY_DEFINED
#else
#define yyensure_buffer_stack hsql_ensure_buffer_stack
#endif
#ifdef yylex
#define hsql_lex_ALREADY_DEFINED
#else
#define yylex hsql_lex
#endif
#ifdef yyrestart
#define hsql_restart_ALREADY_DEFINED
#else
#define yyrestart hsql_restart
#endif
#ifdef yylex_init
#define hsql_lex_init_ALREADY_DEFINED
#else
#define yylex_init hsql_lex_init
#endif
#ifdef yylex_init_extra
#define hsql_lex_init_extra_ALREADY_DEFINED
#else
#define yylex_init_extra hsql_lex_init_extra
#endif
#ifdef yylex_destroy
#define hsql_lex_destroy_ALREADY_DEFINED
#else
#define yylex_destroy hsql_lex_destroy
#endif
#ifdef yyget_debug
#define hsql_get_debug_ALREADY_DEFINED
#else
#define yyget_debug hsql_get_debug
#endif
#ifdef yyset_debug
#define hsql_set_debug_ALREADY_DEFINED
#else
#define yyset_debug hsql_set_debug
#endif
#ifdef yyget_extra
#define hsql_get_extra_ALREADY_DEFINED
#else
#define yyget_extra hsql_get_extra
#endif
#ifdef yyset_extra
#define hsql_set_extra_ALREADY_DEFINED
#else
#define yyset_extra hsql_set_extra
#endif
#ifdef yyget_in
#define hsql_get_in_ALREADY_DEFINED
#else
#define yyget_in hsql_get_in
#endif
#ifdef yyset_in
#define hsql_set_in_ALREADY_DEFINED
#else
#define yyset_in hsql_set_in
#endif
#ifdef yyget_out
#define hsql_get_out_ALREADY_DEFINED
#else
#define yyget_out hsql_get_out
#endif
#ifdef yyset_out
#define hsql_set_out_ALREADY_DEFINED
#else
#define yyset_out hsql_set_out
#endif
#ifdef yyget_leng
#define hsql_get_leng_ALREADY_DEFINED
#else
#define yyget_leng hsql_get_leng
#endif
#ifdef yyget_text
#define hsql_get_text_ALREADY_DEFINED
#else
#define yyget_text hsql_get_text
#endif
#ifdef yyget_lineno
#define hsql_get_lineno_ALREADY_DEFINED
#else
#define yyget_lineno hsql_get_lineno
#endif
#ifdef yyset_lineno
#define hsql_set_lineno_ALREADY_DEFINED
#else
#define yyset_lineno hsql_set_lineno
#endif
#ifdef yyget_column
#define hsql_get_column_ALREADY_DEFINED
#else
#define yyget_column hsql_get_column
#endif
#ifdef yyset_column
#define hsql_set_column_ALREADY_DEFINED
#else
#define yyset_column hsql_set_column
#endif
#ifdef yywrap
#define hsql_wrap_ALREADY_DEFINED
#else
#define yywrap hsql_wrap
#endif
#ifdef yyget_lval
#define hsql_get_lval_ALREADY_DEFINED
#else
#define yyget_lval hsql_get_lval
#endif
#ifdef yyset_lval
#define hsql_set_lval_ALREADY_DEFINED
#else
#define yyset_lval hsql_set_lval
#endif
#ifdef yyget_lloc
#define hsql_get_lloc_ALREADY_DEFINED
#else
#define yyget_lloc hsql_get_lloc
#endif
#ifdef yyset_lloc
#define hsql_set_lloc_ALREADY_DEFINED
#else
#define yyset_lloc hsql_set_lloc
#endif
#ifdef yyalloc
#define hsql_alloc_ALREADY_DEFINED
#else
#define yyalloc hsql_alloc
#endif
#ifdef yyrealloc
#define hsql_realloc_ALREADY_DEFINED
#else
#define yyrealloc hsql_realloc
#endif
#ifdef yyfree
#define hsql_free_ALREADY_DEFINED
#else
#define yyfree hsql_free
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
@ -322,16 +88,10 @@ typedef unsigned int flex_uint32_t;
#define UINT32_MAX (4294967295U)
#endif
#ifndef SIZE_MAX
#define SIZE_MAX (~(size_t)0)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
/* begin standard C++ headers. */
/* TODO: this is always defined, so inline it */
#define yyconst const
@ -432,21 +192,21 @@ struct yy_buffer_state
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
void yypop_buffer_state ( yyscan_t yyscanner );
void hsql_restart (FILE *input_file ,yyscan_t yyscanner );
void hsql__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
YY_BUFFER_STATE hsql__create_buffer (FILE *file,int size ,yyscan_t yyscanner );
void hsql__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
void hsql__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
void hsql_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
void hsql_pop_buffer_state (yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
YY_BUFFER_STATE hsql__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
YY_BUFFER_STATE hsql__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
YY_BUFFER_STATE hsql__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
void yyfree ( void * , yyscan_t yyscanner );
void *hsql_alloc (yy_size_t ,yyscan_t yyscanner );
void *hsql_realloc (void *,yy_size_t ,yyscan_t yyscanner );
void hsql_free (void * ,yyscan_t yyscanner );
/* Begin user sect3 */
@ -473,50 +233,50 @@ void yyfree ( void * , yyscan_t yyscanner );
#define YY_EXTRA_TYPE void *
#endif
int yylex_init (yyscan_t* scanner);
int hsql_lex_init (yyscan_t* scanner);
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
int hsql_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy ( yyscan_t yyscanner );
int hsql_lex_destroy (yyscan_t yyscanner );
int yyget_debug ( yyscan_t yyscanner );
int hsql_get_debug (yyscan_t yyscanner );
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
void hsql_set_debug (int debug_flag ,yyscan_t yyscanner );
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
YY_EXTRA_TYPE hsql_get_extra (yyscan_t yyscanner );
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
void hsql_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
FILE *yyget_in ( yyscan_t yyscanner );
FILE *hsql_get_in (yyscan_t yyscanner );
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
void hsql_set_in (FILE * _in_str ,yyscan_t yyscanner );
FILE *yyget_out ( yyscan_t yyscanner );
FILE *hsql_get_out (yyscan_t yyscanner );
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
void hsql_set_out (FILE * _out_str ,yyscan_t yyscanner );
int yyget_leng ( yyscan_t yyscanner );
int hsql_get_leng (yyscan_t yyscanner );
char *yyget_text ( yyscan_t yyscanner );
char *hsql_get_text (yyscan_t yyscanner );
int yyget_lineno ( yyscan_t yyscanner );
int hsql_get_lineno (yyscan_t yyscanner );
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
void hsql_set_lineno (int _line_number ,yyscan_t yyscanner );
int yyget_column ( yyscan_t yyscanner );
int hsql_get_column (yyscan_t yyscanner );
void yyset_column ( int _column_no , yyscan_t yyscanner );
void hsql_set_column (int _column_no ,yyscan_t yyscanner );
YYSTYPE * yyget_lval ( yyscan_t yyscanner );
YYSTYPE * hsql_get_lval (yyscan_t yyscanner );
void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
void hsql_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
YYLTYPE *hsql_get_lloc (yyscan_t yyscanner );
void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
void hsql_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
@ -524,18 +284,18 @@ void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap ( yyscan_t yyscanner );
extern "C" int hsql_wrap (yyscan_t yyscanner );
#else
extern int yywrap ( yyscan_t yyscanner );
extern int hsql_wrap (yyscan_t yyscanner );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
@ -563,10 +323,10 @@ static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex \
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
extern int hsql_lex \
(YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
#define YY_DECL int yylex \
#define YY_DECL int hsql_lex \
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
#endif /* !YY_DECL */
@ -584,154 +344,9 @@ extern int yylex \
#undef YY_DECL
#endif
#ifndef hsql__create_buffer_ALREADY_DEFINED
#undef yy_create_buffer
#endif
#ifndef hsql__delete_buffer_ALREADY_DEFINED
#undef yy_delete_buffer
#endif
#ifndef hsql__scan_buffer_ALREADY_DEFINED
#undef yy_scan_buffer
#endif
#ifndef hsql__scan_string_ALREADY_DEFINED
#undef yy_scan_string
#endif
#ifndef hsql__scan_bytes_ALREADY_DEFINED
#undef yy_scan_bytes
#endif
#ifndef hsql__init_buffer_ALREADY_DEFINED
#undef yy_init_buffer
#endif
#ifndef hsql__flush_buffer_ALREADY_DEFINED
#undef yy_flush_buffer
#endif
#ifndef hsql__load_buffer_state_ALREADY_DEFINED
#undef yy_load_buffer_state
#endif
#ifndef hsql__switch_to_buffer_ALREADY_DEFINED
#undef yy_switch_to_buffer
#endif
#ifndef hsql_push_buffer_state_ALREADY_DEFINED
#undef yypush_buffer_state
#endif
#ifndef hsql_pop_buffer_state_ALREADY_DEFINED
#undef yypop_buffer_state
#endif
#ifndef hsql_ensure_buffer_stack_ALREADY_DEFINED
#undef yyensure_buffer_stack
#endif
#ifndef hsql_lex_ALREADY_DEFINED
#undef yylex
#endif
#ifndef hsql_restart_ALREADY_DEFINED
#undef yyrestart
#endif
#ifndef hsql_lex_init_ALREADY_DEFINED
#undef yylex_init
#endif
#ifndef hsql_lex_init_extra_ALREADY_DEFINED
#undef yylex_init_extra
#endif
#ifndef hsql_lex_destroy_ALREADY_DEFINED
#undef yylex_destroy
#endif
#ifndef hsql_get_debug_ALREADY_DEFINED
#undef yyget_debug
#endif
#ifndef hsql_set_debug_ALREADY_DEFINED
#undef yyset_debug
#endif
#ifndef hsql_get_extra_ALREADY_DEFINED
#undef yyget_extra
#endif
#ifndef hsql_set_extra_ALREADY_DEFINED
#undef yyset_extra
#endif
#ifndef hsql_get_in_ALREADY_DEFINED
#undef yyget_in
#endif
#ifndef hsql_set_in_ALREADY_DEFINED
#undef yyset_in
#endif
#ifndef hsql_get_out_ALREADY_DEFINED
#undef yyget_out
#endif
#ifndef hsql_set_out_ALREADY_DEFINED
#undef yyset_out
#endif
#ifndef hsql_get_leng_ALREADY_DEFINED
#undef yyget_leng
#endif
#ifndef hsql_get_text_ALREADY_DEFINED
#undef yyget_text
#endif
#ifndef hsql_get_lineno_ALREADY_DEFINED
#undef yyget_lineno
#endif
#ifndef hsql_set_lineno_ALREADY_DEFINED
#undef yyset_lineno
#endif
#ifndef hsql_get_column_ALREADY_DEFINED
#undef yyget_column
#endif
#ifndef hsql_set_column_ALREADY_DEFINED
#undef yyset_column
#endif
#ifndef hsql_wrap_ALREADY_DEFINED
#undef yywrap
#endif
#ifndef hsql_get_lval_ALREADY_DEFINED
#undef yyget_lval
#endif
#ifndef hsql_set_lval_ALREADY_DEFINED
#undef yyset_lval
#endif
#ifndef hsql_get_lloc_ALREADY_DEFINED
#undef yyget_lloc
#endif
#ifndef hsql_set_lloc_ALREADY_DEFINED
#undef yyset_lloc
#endif
#ifndef hsql_alloc_ALREADY_DEFINED
#undef yyalloc
#endif
#ifndef hsql_realloc_ALREADY_DEFINED
#undef yyrealloc
#endif
#ifndef hsql_free_ALREADY_DEFINED
#undef yyfree
#endif
#ifndef hsql_text_ALREADY_DEFINED
#undef yytext
#endif
#ifndef hsql_leng_ALREADY_DEFINED
#undef yyleng
#endif
#ifndef hsql_in_ALREADY_DEFINED
#undef yyin
#endif
#ifndef hsql_out_ALREADY_DEFINED
#undef yyout
#endif
#ifndef hsql__flex_debug_ALREADY_DEFINED
#undef yy_flex_debug
#endif
#ifndef hsql_lineno_ALREADY_DEFINED
#undef yylineno
#endif
#ifndef hsql_tables_fload_ALREADY_DEFINED
#undef yytables_fload
#endif
#ifndef hsql_tables_destroy_ALREADY_DEFINED
#undef yytables_destroy
#endif
#ifndef hsql_TABLES_NAME_ALREADY_DEFINED
#undef yyTABLES_NAME
#endif
#line 217 "flex_lexer.l"
#line 735 "flex_lexer.h"
#line 351 "flex_lexer.h"
#undef hsql_IN_HEADER
#endif /* hsql_HEADER_H */

1
src/sql/CreateStatement.h Normal file → Executable file
View File

@ -38,6 +38,7 @@ namespace hsql {
CreateType type;
bool ifNotExists; // default: false
char* filePath; // default: nullptr
char* schema; // default: nullptr
char* tableName; // default: nullptr
std::vector<ColumnDefinition*>* columns; // default: nullptr
std::vector<char*>* viewColumns;

1
src/sql/DeleteStatement.h Normal file → Executable file
View File

@ -13,6 +13,7 @@ namespace hsql {
DeleteStatement();
virtual ~DeleteStatement();
char* schema;
char* tableName;
Expr* expr;
};

2
src/sql/DropStatement.h Normal file → Executable file
View File

@ -22,6 +22,8 @@ namespace hsql {
virtual ~DropStatement();
DropType type;
bool ifExists;
char* schema;
char* name;
};

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,

5
src/sql/ImportStatement.h Normal file → Executable file
View File

@ -15,8 +15,9 @@ namespace hsql {
virtual ~ImportStatement();
ImportType type;
const char* filePath;
const char* tableName;
char* filePath;
char* schema;
char* tableName;
};
} // namespace hsql

1
src/sql/InsertStatement.h Normal file → Executable file
View File

@ -17,6 +17,7 @@ namespace hsql {
virtual ~InsertStatement();
InsertType type;
char* schema;
char* tableName;
std::vector<char*>* columns;
std::vector<Expr*>* values;

View File

@ -19,7 +19,8 @@ namespace hsql {
kStmtExecute,
kStmtExport,
kStmtRename,
kStmtAlter
kStmtAlter,
kStmtShow
};
// Base struct for every SQL statement

27
src/sql/ShowStatement.h Executable file
View File

@ -0,0 +1,27 @@
#ifndef __SQLPARSER__SHOW_STATEMENT_H__
#define __SQLPARSER__SHOW_STATEMENT_H__
#include "SQLStatement.h"
// Note: Implementations of constructors and destructors can be found in statements.cpp.
namespace hsql {
enum ShowType {
kShowColumns,
kShowTables
};
// Represents SQL SHOW statements.
// Example "SHOW TABLES;"
struct ShowStatement : SQLStatement {
ShowStatement(ShowType type);
virtual ~ShowStatement();
ShowType type;
char* schema;
char* name;
};
} // namespace hsql
#endif

5
src/sql/Table.h Normal file → Executable file
View File

@ -19,6 +19,11 @@ namespace hsql {
kTableCrossProduct
};
struct TableName {
char* schema;
char* name;
};
// Holds reference to tables. Can be either table names or a select statement.
struct TableRef {
TableRef(TableRefType type);

26
src/sql/statements.cpp Normal file → Executable file
View File

@ -18,6 +18,7 @@ namespace hsql {
type(type),
ifNotExists(false),
filePath(nullptr),
schema(nullptr),
tableName(nullptr),
columns(nullptr),
viewColumns(nullptr),
@ -25,6 +26,7 @@ namespace hsql {
CreateStatement::~CreateStatement() {
free(filePath);
free(schema);
free(tableName);
delete select;
@ -46,10 +48,12 @@ namespace hsql {
// DeleteStatement
DeleteStatement::DeleteStatement() :
SQLStatement(kStmtDelete),
schema(nullptr),
tableName(nullptr),
expr(nullptr) {};
DeleteStatement::~DeleteStatement() {
free(schema);
free(tableName);
delete expr;
}
@ -58,9 +62,11 @@ namespace hsql {
DropStatement::DropStatement(DropType type) :
SQLStatement(kStmtDrop),
type(type),
schema(nullptr),
name(nullptr) {}
DropStatement::~DropStatement() {
free(schema);
free(name);
}
@ -86,23 +92,27 @@ namespace hsql {
SQLStatement(kStmtImport),
type(type),
filePath(nullptr),
schema(nullptr),
tableName(nullptr) {};
ImportStatement::~ImportStatement() {
delete filePath;
delete tableName;
free(filePath);
free(schema);
free(tableName);
}
// InsertStatement
InsertStatement::InsertStatement(InsertType type) :
SQLStatement(kStmtInsert),
type(type),
schema(nullptr),
tableName(nullptr),
columns(nullptr),
values(nullptr),
select(nullptr) {}
InsertStatement::~InsertStatement() {
free(schema);
free(tableName);
delete select;
@ -121,6 +131,18 @@ namespace hsql {
}
}
// ShowStatament
ShowStatement::ShowStatement(ShowType type) :
SQLStatement(kStmtShow),
type(type),
schema(nullptr),
name(nullptr) {}
ShowStatement::~ShowStatement() {
free(schema);
free(name);
}
// SelectStatement.h
// OrderDescription

View File

@ -10,5 +10,6 @@
#include "DropStatement.h"
#include "PrepareStatement.h"
#include "ExecuteStatement.h"
#include "ShowStatement.h"
#endif // __SQLPARSER__STATEMENTS_H__

25
src/util/sqlhelper.cpp Normal file → Executable file
View File

@ -33,6 +33,10 @@ namespace hsql {
switch (table->type) {
case kTableName:
inprint(table->name, numIndent);
if(table->schema) {
inprint("Schema", numIndent + 1);
inprint(table->schema, numIndent + 2);
}
break;
case kTableSelect:
printSelectStatementInfo(table->select, numIndent);
@ -91,6 +95,10 @@ namespace hsql {
break;
case kExprColumnRef:
inprint(expr->name, numIndent);
if(expr->table) {
inprint("Table:", numIndent+1);
inprint(expr->table, numIndent+2);
}
break;
// case kExprTableColumnRef: inprint(expr->table, expr->name, numIndent); break;
case kExprLiteralFloat:
@ -104,11 +112,24 @@ namespace hsql {
break;
case kExprFunctionRef:
inprint(expr->name, numIndent);
for (Expr* e : *expr->exprList) inprint(e->name, numIndent + 1);
for (Expr* e : *expr->exprList) printExpression(e, numIndent + 1);
break;
case kExprOperator:
printOperatorExpression(expr, numIndent);
break;
case kExprSelect:
printSelectStatementInfo(expr->select, numIndent);
break;
case kExprParameter:
inprint(expr->ival, numIndent);
break;
case kExprArray:
for (Expr* e : *expr->exprList) printExpression(e, numIndent + 1);
break;
case kExprArrayIndex:
printExpression(expr->expr, numIndent + 1);
inprint(expr->ival, numIndent);
break;
default:
std::cerr << "Unrecognized expression type " << expr->type << std::endl;
return;
@ -124,8 +145,10 @@ namespace hsql {
inprint("Fields:", numIndent + 1);
for (Expr* expr : *stmt->selectList) printExpression(expr, numIndent + 2);
if (stmt->fromTable != nullptr) {
inprint("Sources:", numIndent + 1);
printTableRefInfo(stmt->fromTable, numIndent + 2);
}
if (stmt->whereClause != nullptr) {
inprint("Search Conditions:", numIndent + 1);

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,12 @@
# 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;
!SHOW COLUMNS;

View File

@ -1,6 +1,9 @@
# 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
SELECT a FROM some_schema.foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10
SELECT col1 AS myname, col2, 'test' FROM "table", foo AS t WHERE age > 12 AND zipcode = 12345 GROUP BY col1;
SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5
(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10);
@ -27,6 +30,7 @@ CREATE TABLE "table" FROM TBL FILE 'students.tbl'; SELECT * FROM "table";
INSERT INTO test_table VALUES (1, 2, 'test');
INSERT INTO test_table (id, value, name) VALUES (1, 2, 'test');
INSERT INTO test_table SELECT * FROM students;
INSERT INTO some_schema.test_table SELECT * FROM another_schema.students;
# DELETE
DELETE FROM students WHERE grade > 3.0
DELETE FROM students
@ -35,8 +39,11 @@ TRUNCATE students
UPDATE students SET grade = 1.3 WHERE name = 'Max Mustermann';
UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann';
UPDATE students SET grade = 1.0;
UPDATE some_schema.students SET grade = 1.0;
# DROP
DROP TABLE students;
DROP TABLE IF EXISTS students;
DROP VIEW IF EXISTS students;
# PREPARE
PREPARE prep_inst FROM 'INSERT INTO test VALUES (?, ?, ?)';
PREPARE prep2 FROM 'INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?, 0); INSERT INTO test VALUES (0, 0, ?);';
@ -47,12 +54,5 @@ 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;
SHOW TABLES;
SHOW COLUMNS students;

View File

@ -88,6 +88,18 @@ TEST(SelectDistinctTest) {
ASSERT_NULL(stmt->whereClause);
}
TEST(SelectSchemaTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT grade FROM some_schema.students;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT(stmt->fromTable);
ASSERT_EQ(std::string(stmt->fromTable->schema), "some_schema");
}
TEST(SelectGroupDistinctTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;",

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

@ -102,6 +102,21 @@ TEST(DropTableStatementTest) {
result,
stmt);
ASSERT_FALSE(stmt->ifExists);
ASSERT_EQ(stmt->type, kDropTable);
ASSERT_NOTNULL(stmt->name);
ASSERT_STREQ(stmt->name, "students");
}
TEST(DropTableIfExistsStatementTest) {
TEST_PARSE_SINGLE_SQL(
"DROP TABLE IF EXISTS students",
kStmtDrop,
DropStatement,
result,
stmt);
ASSERT_TRUE(stmt->ifExists);
ASSERT_EQ(stmt->type, kDropTable);
ASSERT_NOTNULL(stmt->name);
ASSERT_STREQ(stmt->name, "students");
@ -127,6 +142,31 @@ TEST(ReleaseStatementTest) {
}
}
TEST(ShowTableStatementTest) {
TEST_PARSE_SINGLE_SQL(
"SHOW TABLES;",
kStmtShow,
ShowStatement,
result,
stmt);
ASSERT_EQ(stmt->type, kShowTables);
ASSERT_NULL(stmt->name);
}
TEST(ShowColumnsStatementTest) {
TEST_PARSE_SINGLE_SQL(
"SHOW COLUMNS students;",
kStmtShow,
ShowStatement,
result,
stmt);
ASSERT_EQ(stmt->type, kShowColumns);
ASSERT_NOTNULL(stmt->name);
ASSERT_STREQ(stmt->name, "students");
}
SQLParserResult parse_and_move(std::string query) {
hsql::SQLParserResult result;

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