Merge pull request #12 from torpedro/api-cleanup

Improve API & formatting. Adds clang support & travis ci
This commit is contained in:
Pedro Flemming 2016-02-27 17:49:32 +01:00
commit 7cfae24503
46 changed files with 1451 additions and 1400 deletions

3
.gitignore vendored
View File

@ -31,3 +31,6 @@ lib-test/
*.exe *.exe
*.out *.out
*.app *.app
*.cpp.orig
*.h.orig

20
.travis.yml Normal file
View File

@ -0,0 +1,20 @@
language: cpp
install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get -qq update
- sudo apt-get install -y bison flex
- sudo apt-get install -y g++-4.8 libstdc++-4.8-dev
- 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
- which g++
- g++ -v
compiler:
- gcc
- clang
script:
- make
- make test

View File

@ -9,25 +9,27 @@ LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(S
LIBOBJ = $(LIBCPP:%.cpp=%.o) LIBOBJ = $(LIBCPP:%.cpp=%.o)
TESTCPP = $(shell find test/lib/ -name '*.cpp') TESTCPP = $(shell find test/lib/ -name '*.cpp')
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
# compile & link flages # compile & link flages
CC = g++
CFLAGS = -std=c++11 -Wall -fPIC CFLAGS = -std=c++11 -Wall -fPIC
LIBFLAGS = -shared LIBFLAGS = -shared
TARGET = libsqlparser.so TARGET = libsqlparser.so
INSTALL = /usr/local INSTALL = /usr/local
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++
all: library all: library
library: $(TARGET) library: $(TARGET)
$(TARGET): $(LIBOBJ) $(TARGET): $(LIBOBJ)
$(CC) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ) $(CXX) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ)
%.o: %.cpp $(PARSERFILES) %.o: %.cpp $(PARSERFILES)
$(CC) $(CFLAGS) -c -o $@ $< $(CXX) $(CFLAGS) -c -o $@ $<
$(SRCPARSER)/bison_parser.cpp: parser $(SRCPARSER)/bison_parser.cpp: parser
$(SRCPARSER)/flex_lexer.cpp: parser $(SRCPARSER)/flex_lexer.cpp: parser
@ -48,20 +50,26 @@ cleanall: clean cleanparser
install: install:
cp $(TARGET) $(INSTALL)/lib/$(TARGET) cp $(TARGET) $(INSTALL)/lib/$(TARGET)
format:
astyle --options=astyle.options $(ALLLIB)
astyle --options=astyle.options $(ALLTEST)
############ ############
### Test ### ### Test ###
############ ############
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
LD_LIBRARY_PATH=./ $(BIN)/sql_grammar_test -f "test/lib/valid_queries.sql" bash test/test.sh
LD_LIBRARY_PATH=./ $(BIN)/sql_tests
# test whete
test_install:
make -C example/
./example/example "SELECT * FROM students WHERE name = 'Max Mustermann';"
$(BIN)/sql_tests: library $(BIN)/sql_tests: library
@mkdir -p $(BIN)/ @mkdir -p $(BIN)/
$(CC) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser $(CXX) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser
$(BIN)/sql_grammar_test: library $(BIN)/sql_grammar_test: library
@mkdir -p $(BIN)/ @mkdir -p $(BIN)/
$(CC) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser $(CXX) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser

View File

@ -9,18 +9,23 @@ In March 2015 we've also written a short paper outlining discussing some develop
### Usage ### Usage
To use the SQL parser in your own projects you simply have to follow these few steps. The only requirement for is GCC 4.8+. Older versions of GCC probably also work, but are untested. **Requirements:**
* gcc 4.8+
To use the SQL parser in your own projects you simply have to follow these few steps. The only requirement for is gcc 4.8+. Older versions of gcc might also work, but are untested.
1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases) 1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases)
2. Compile the library `make` to create `libsqlparser.so` 2. Compile the library `make` to create `libsqlparser.so`
3. *(Optional)* Run `make install` to copy the library to `/usr/local/lib/`
3. Run the tests `make test` to make sure everything worked 3. Run the tests `make test` to make sure everything worked
4. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/dynamic-library/example) 4. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/master/example)
5. Include the `SQLParser.h` from `src/` and link the library in your project 5. Include the `SQLParser.h` from `src/` and link the library in your project
### Development ### Development
**Prerequisites:** **Requirements for development:**
* gcc 4.8 (or newer)
* [bison](https://www.gnu.org/software/bison/) (tested with v3.0.2) * [bison](https://www.gnu.org/software/bison/) (tested with v3.0.2)
* [flex](http://flex.sourceforge.net/) (tested with v2.5.5) * [flex](http://flex.sourceforge.net/) (tested with v2.5.5)
@ -45,12 +50,10 @@ make test # build parser, library and runs the tests
We strongly encourage you to contribute to this project! If you want to contribute to this project there are several options. If you've noticed a bug or would like an improvement let us know by creating a [new issue](https://github.com/hyrise/sql-parser/issues). If you want to develop a new feature yourself or just improve the quality of the system, feel free to fork the reposistory and implement your changes. Open a pull request as soon as your done and we will look over it. If we think it's good then your pull request will be merged into this repository. We strongly encourage you to contribute to this project! If you want to contribute to this project there are several options. If you've noticed a bug or would like an improvement let us know by creating a [new issue](https://github.com/hyrise/sql-parser/issues). If you want to develop a new feature yourself or just improve the quality of the system, feel free to fork the reposistory and implement your changes. Open a pull request as soon as your done and we will look over it. If we think it's good then your pull request will be merged into this repository.
### Documenation ### Resources
* [Working Syntax Examples](docs/syntax.md) * [Working Syntax Examples](docs/syntax.md)
* [Known Issues](docs/issues.md) * [Developer Documentation](docs/dev-docs.md)
* [Developer Documentation](docs/documentation.md)
* [Integration in Hyrise](docs/integration.md)
### License ### License

8
astyle.options Normal file
View File

@ -0,0 +1,8 @@
# indentation
--indent=spaces=4
--indent-namespaces
--style=java
--style=attach
-A2

View File

@ -1,29 +1,31 @@
Developer Documentation Developer Documentation
======================= =======================
This page contains information about how to extend this parser with new functionalities. ## Developing New Functionality
This section contains information about how to extend this parser with new functionalities.
### Implementing a new Statement
## Implementing Statement Class Create a new file and class in `src/sql/` or extend any of the existing Statements. Every statement needs to have the base class SQLStatement and needs to call its super constructor with its type. If your defining a new statement type, you need to define a new StatementType in `SQLStatement.h`.
Create a new file and class in src/lib/statements/ or extend any of the existing Statements. Every statement needs to have the base class SQLStatement and needs to call its super constructor with its type. If your defining a new statement type, you need to define a new StatementType in SQLStatement.h.
It is important that you create an appropriate constructor for your statement that zero-initializes all its pointer variables and that your create an appropriate destructor. It is important that you create an appropriate constructor for your statement that zero-initializes all its pointer variables and that your create an appropriate destructor.
Lastly you need to include your new file in src/lib/sqllib.h Finally you will need to include your new file in `src/sql/statements.h`.
### Extending the Grammar
## Extending the Grammar
Related files: Related files:
* src/parser/bison_parser.y ````
* src/parser/flex_lexer.l src/parser/bison_parser.y
* src/parser/keywordlist_generator.py src/parser/flex_lexer.l
* src/parser/sql_keywords.txt src/parser/keywordlist_generator.py
src/parser/sql_keywords.txt
```
To extend the grammar the file you will mostly have to deal with is the bison grammar definition in src/parser/bison_parser.y. To extend the grammar the file you will mostly have to deal with is the bison grammar definition in `src/parser/bison_parser.y`.
If your extending an existing statement, skip to the non-terminal definition for that statement. I.e. for an InsertStatement the non-terminal insert_statement. If your extending an existing statement, skip to the non-terminal definition for that statement. I.e. for an InsertStatement the non-terminal insert_statement.
@ -33,7 +35,6 @@ If your defining a new statement, you will need to define your type in the \%uni
## Implementing Tests ## Implementing Tests
Related files: All test related files are in `test/`. Take a look to see how tests are implemented.
* src/sql_tests.cpp

View File

@ -1,20 +0,0 @@
@PROJECT_NAME = "SQL Parser for Hyrise (C++)"
@OUTPUT_DIRECTORY = docs/__doxygen__/
@GENERATE_LATEX = NO
@GENERATE_HTML = YES
@INCLUDE_FILE_PATTERNS = *.y *.l
@FILE_PATTERNS = *.y *.l *.h *.cpp *.md
@INPUT = README.md \
docs/ \
src/parser/SQLParser.h \
src/parser/SQLParser.cpp \
src/parser/bison_parser.y \
src/parser/flex_lexer.l \
src/lib/ \
@RECURSIVE = YES

View File

@ -1,8 +0,0 @@
Integration in Hyrise
=====================
On this page we describe how to integrate changes to the parser into Hyrise.
## Update the Parser code in Hyrise
Run `./deploy_to_hyrise.sh path/to/hyrise` to update the SQL parser code within Hyrise.

View File

@ -1,10 +0,0 @@
Known Issues
============
Here we will keep track of issues with the parser and the integration in Hyrise.
## Missing Functionality
* Union clauses
* Create anything other than tables
* Alter/Rename statements

View File

@ -1,7 +1,6 @@
CC = g++ CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../
CFLAGS = -std=c++11 -Wall -I../src/ -L../
all: all:
$(CC) $(CFLAGS) example.cpp -o example -lsqlparser $(CXX) $(CFLAGS) example.cpp -o example -lsqlparser

View File

@ -16,20 +16,21 @@ int main(int argc, char *argv[]) {
std::string query = argv[1]; std::string query = argv[1];
// parse a given query // parse a given query
hsql::SQLStatementList* result = hsql::SQLParser::parseSQLString(query); hsql::SQLParserResult* result = hsql::SQLParser::parseSQLString(query);
// check whether the parsing was successful // check whether the parsing was successful
if (result->isValid) { if (result->isValid) {
printf("Parsed successfully!\n"); printf("Parsed successfully!\n");
printf("Number of statements: %lu\n", result->numStatements()); printf("Number of statements: %lu\n", result->size());
for (hsql::SQLStatement* stmt : result->statements) { for (hsql::SQLStatement* stmt : result->statements) {
// process the statements... // process the statements...
hsql::printStatementInfo(stmt); hsql::printStatementInfo(stmt);
} }
} else {
printf("Invalid SQL!\n");
}
return 0; return 0;
} else {
printf("Invalid SQL!\n");
return -1;
}
} }

View File

@ -13,8 +13,8 @@ SQLParser::SQLParser() {
} }
SQLStatementList* SQLParser::parseSQLString(const char *text) { SQLParserResult* SQLParser::parseSQLString(const char *text) {
SQLStatementList* result; SQLParserResult* result = NULL;
yyscan_t scanner; yyscan_t scanner;
YY_BUFFER_STATE state; YY_BUFFER_STATE state;
@ -37,7 +37,8 @@ SQLStatementList* SQLParser::parseSQLString(const char *text) {
return result; return result;
} }
SQLStatementList* SQLParser::parseSQLString(const std::string& text) {
SQLParserResult* SQLParser::parseSQLString(const std::string& text) {
return parseSQLString(text.c_str()); return parseSQLString(text.c_str());
} }

View File

@ -1,21 +1,17 @@
#ifndef __SQLPARSER_H_ #ifndef __SQLPARSER_H_
#define __SQLPARSER_H_ #define __SQLPARSER_H_
#include "sqltypes.h" #include "SQLParserResult.h"
#include "sql/statements.h"
namespace hsql { namespace hsql {
/**
/*! * Main class for parsing SQL strings
* \mainpage SQLParser (C++)
*/
/*!
* @brief Main class for parsing SQL strings
*/ */
class SQLParser { class SQLParser {
public: public:
static SQLStatementList* parseSQLString(const char* sql); static SQLParserResult* parseSQLString(const char* sql);
static SQLStatementList* parseSQLString(const std::string& sql); static SQLParserResult* parseSQLString(const std::string& sql);
private: private:
SQLParser(); SQLParser();

41
src/SQLParserResult.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "SQLParserResult.h"
namespace hsql {
SQLParserResult::SQLParserResult() :
isValid(true),
errorMsg(NULL) {};
SQLParserResult::SQLParserResult(SQLStatement* stmt) :
isValid(true),
errorMsg(NULL) {
addStatement(stmt);
};
SQLParserResult::~SQLParserResult() {
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
delete *it;
}
delete errorMsg;
}
void SQLParserResult::addStatement(SQLStatement* stmt) {
statements.push_back(stmt);
}
SQLStatement* SQLParserResult::getStatement(int id) {
return statements[id];
}
size_t SQLParserResult::size() {
return statements.size();
}
} // namespace hsql

35
src/SQLParserResult.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __SQLPARSERRESULT__
#define __SQLPARSERRESULT__
#include "sql/SQLStatement.h"
namespace hsql {
/**
* Represents the result of the SQLParser.
* If parsing was successful it contains a list of SQLStatement.
*/
class SQLParserResult {
public:
SQLParserResult();
SQLParserResult(SQLStatement* stmt);
virtual ~SQLParserResult();
void addStatement(SQLStatement* stmt);
SQLStatement* getStatement(int id);
size_t size();
// public properties
std::vector<SQLStatement*> statements;
bool isValid;
const char* errorMsg;
int errorLine;
int errorColumn;
};
} // namespace hsql
#endif // __SQLPARSERRESULT__

File diff suppressed because it is too large Load Diff

View File

@ -48,9 +48,12 @@
extern int hsql_debug; extern int hsql_debug;
#endif #endif
/* "%code requires" blocks. */ /* "%code requires" blocks. */
#line 43 "bison_parser.y" /* yacc.c:1909 */ #line 42 "bison_parser.y" /* yacc.c:1909 */
// %code requires block // %code requires block
#include "../sql/statements.h"
#include "../SQLParserResult.h"
#include "parser_typedef.h" #include "parser_typedef.h"
// Auto update column and line number // Auto update column and line number
@ -68,7 +71,7 @@ extern int hsql_debug;
} \ } \
} }
#line 72 "bison_parser.h" /* yacc.c:1909 */ #line 75 "bison_parser.h" /* yacc.c:1909 */
/* Token type. */ /* Token type. */
#ifndef HSQL_TOKENTYPE #ifndef HSQL_TOKENTYPE
@ -206,7 +209,7 @@ extern int hsql_debug;
typedef union HSQL_STYPE HSQL_STYPE; typedef union HSQL_STYPE HSQL_STYPE;
union HSQL_STYPE union HSQL_STYPE
{ {
#line 99 "bison_parser.y" /* yacc.c:1909 */ #line 101 "bison_parser.y" /* yacc.c:1909 */
double fval; double fval;
int64_t ival; int64_t ival;
@ -234,7 +237,7 @@ union HSQL_STYPE
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::SQLStatementList* stmt_list; hsql::SQLParserResult* stmt_list;
std::vector<char*>* str_vec; std::vector<char*>* str_vec;
std::vector<hsql::TableRef*>* table_vec; std::vector<hsql::TableRef*>* table_vec;
@ -242,7 +245,7 @@ union HSQL_STYPE
std::vector<hsql::UpdateClause*>* update_vec; std::vector<hsql::UpdateClause*>* update_vec;
std::vector<hsql::Expr*>* expr_vec; std::vector<hsql::Expr*>* expr_vec;
#line 246 "bison_parser.h" /* yacc.c:1909 */ #line 249 "bison_parser.h" /* yacc.c:1909 */
}; };
# define HSQL_STYPE_IS_TRIVIAL 1 # define HSQL_STYPE_IS_TRIVIAL 1
# define HSQL_STYPE_IS_DECLARED 1 # define HSQL_STYPE_IS_DECLARED 1
@ -264,6 +267,6 @@ struct HSQL_LTYPE
int hsql_parse (hsql::SQLStatementList** result, yyscan_t scanner); int hsql_parse (hsql::SQLParserResult** result, yyscan_t scanner);
#endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */ #endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */

View File

@ -11,7 +11,6 @@
** Section 1: C Declarations ** Section 1: C Declarations
*********************************/ *********************************/
#include "../sqltypes.h"
#include "bison_parser.h" #include "bison_parser.h"
#include "flex_lexer.h" #include "flex_lexer.h"
@ -19,13 +18,13 @@
using namespace hsql; using namespace hsql;
int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const char *msg) { int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const char *msg) {
SQLStatementList* list = new SQLStatementList(); SQLParserResult* list = new SQLParserResult();
list->isValid = false; list->isValid = false;
list->parser_msg = strdup(msg); list->errorMsg = strdup(msg);
list->error_line = llocp->first_line; list->errorLine = llocp->first_line;
list->error_col = llocp->first_column; list->errorColumn = llocp->first_column;
*result = list; *result = list;
return 0; return 0;
@ -42,6 +41,9 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
// Specify code that is included in the generated .h and .c files // Specify code that is included in the generated .h and .c files
%code requires { %code requires {
// %code requires block // %code requires block
#include "../sql/statements.h"
#include "../SQLParserResult.h"
#include "parser_typedef.h" #include "parser_typedef.h"
// Auto update column and line number // Auto update column and line number
@ -89,7 +91,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
%lex-param { yyscan_t scanner } %lex-param { yyscan_t scanner }
// Define additional parameters for yyparse // Define additional parameters for yyparse
%parse-param { hsql::SQLStatementList** result } %parse-param { hsql::SQLParserResult** result }
%parse-param { yyscan_t scanner } %parse-param { yyscan_t scanner }
@ -123,7 +125,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::SQLStatementList* stmt_list; hsql::SQLParserResult* stmt_list;
std::vector<char*>* str_vec; std::vector<char*>* str_vec;
std::vector<hsql::TableRef*>* table_vec; std::vector<hsql::TableRef*>* table_vec;
@ -231,7 +233,7 @@ input:
statement_list: statement_list:
statement { $$ = new SQLStatementList($1); } statement { $$ = new SQLParserResult($1); }
| statement_list ';' statement { $1->addStatement($3); $$ = $1; } | statement_list ';' statement { $1->addStatement($3); $$ = $1; }
; ;
@ -265,7 +267,7 @@ prepare_statement:
PREPARE IDENTIFIER ':' preparable_statement { PREPARE IDENTIFIER ':' preparable_statement {
$$ = new PrepareStatement(); $$ = new PrepareStatement();
$$->name = $2; $$->name = $2;
$$->query = new SQLStatementList($4); $$->query = new SQLParserResult($4);
} }
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' { | PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
$$ = new PrepareStatement(); $$ = new PrepareStatement();
@ -293,8 +295,8 @@ execute_statement:
import_statement: import_statement:
IMPORT FROM import_file_type FILE file_path INTO table_name { IMPORT FROM import_file_type FILE file_path INTO table_name {
$$ = new ImportStatement((ImportStatement::ImportType) $3); $$ = new ImportStatement((ImportStatement::ImportType) $3);
$$->file_path = $5; $$->filePath = $5;
$$->table_name = $7; $$->tableName = $7;
} }
; ;
@ -315,14 +317,14 @@ file_path:
create_statement: create_statement:
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path { CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
$$ = new CreateStatement(CreateStatement::kTableFromTbl); $$ = new CreateStatement(CreateStatement::kTableFromTbl);
$$->if_not_exists = $3; $$->ifNotExists = $3;
$$->table_name = $4; $$->tableName = $4;
$$->file_path = $8; $$->filePath = $8;
} }
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' { | CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
$$ = new CreateStatement(CreateStatement::kTable); $$ = new CreateStatement(CreateStatement::kTable);
$$->if_not_exists = $3; $$->ifNotExists = $3;
$$->table_name = $4; $$->tableName = $4;
$$->columns = $6; $$->columns = $6;
} }
; ;
@ -376,7 +378,7 @@ drop_statement:
delete_statement: delete_statement:
DELETE FROM table_name opt_where { DELETE FROM table_name opt_where {
$$ = new DeleteStatement(); $$ = new DeleteStatement();
$$->table_name = $3; $$->tableName = $3;
$$->expr = $4; $$->expr = $4;
} }
; ;
@ -384,7 +386,7 @@ delete_statement:
truncate_statement: truncate_statement:
TRUNCATE table_name { TRUNCATE table_name {
$$ = new DeleteStatement(); $$ = new DeleteStatement();
$$->table_name = $2; $$->tableName = $2;
} }
; ;
@ -396,13 +398,13 @@ truncate_statement:
insert_statement: insert_statement:
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' { INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
$$ = new InsertStatement(InsertStatement::kInsertValues); $$ = new InsertStatement(InsertStatement::kInsertValues);
$$->table_name = $3; $$->tableName = $3;
$$->columns = $4; $$->columns = $4;
$$->values = $7; $$->values = $7;
} }
| INSERT INTO table_name opt_column_list select_no_paren { | INSERT INTO table_name opt_column_list select_no_paren {
$$ = new InsertStatement(InsertStatement::kInsertSelect); $$ = new InsertStatement(InsertStatement::kInsertSelect);
$$->table_name = $3; $$->tableName = $3;
$$->columns = $4; $$->columns = $4;
$$->select = $5; $$->select = $5;
} }
@ -467,7 +469,7 @@ select_no_paren:
// TODO: capture type of set_operator // TODO: capture type of set_operator
// TODO: might overwrite order and limit of first select here // TODO: might overwrite order and limit of first select here
$$ = $1; $$ = $1;
$$->union_select = $3; $$->unionSelect = $3;
$$->order = $4; $$->order = $4;
$$->limit = $5; $$->limit = $5;
} }
@ -482,11 +484,11 @@ set_operator:
select_clause: select_clause:
SELECT opt_distinct select_list from_clause opt_where opt_group { SELECT opt_distinct select_list from_clause opt_where opt_group {
$$ = new SelectStatement(); $$ = new SelectStatement();
$$->select_distinct = $2; $$->selectDistinct = $2;
$$->select_list = $3; $$->selectList = $3;
$$->from_table = $4; $$->fromTable = $4;
$$->where_clause = $5; $$->whereClause = $5;
$$->group_by = $6; $$->groupBy = $6;
} }
; ;

View File

@ -1545,7 +1545,7 @@ static yyconst flex_int16_t yy_chk[3639] =
***************************/ ***************************/
#line 12 "flex_lexer.l" #line 12 "flex_lexer.l"
#include "../sqltypes.h" #include "../sql/Expr.h"
#include "bison_parser.h" #include "bison_parser.h"
#include <stdio.h> #include <stdio.h>

View File

@ -10,7 +10,7 @@
***************************/ ***************************/
%{ %{
#include "../sqltypes.h" #include "../sql/Expr.h"
#include "bison_parser.h" #include "bison_parser.h"
#include <stdio.h> #include <stdio.h>

View File

@ -4,10 +4,8 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct ColumnDefinition * Represents definition of a table column
* @brief Represents definition of a table column
*/ */
struct ColumnDefinition { struct ColumnDefinition {
enum DataType { enum DataType {
@ -28,41 +26,37 @@ struct ColumnDefinition {
DataType type; DataType type;
}; };
/** /**
* @struct CreateStatement * Represents SQL Create statements.
* @brief Represents "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)" * Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
*/ */
struct CreateStatement : SQLStatement { struct CreateStatement : SQLStatement {
enum CreateType { enum CreateType {
kTable, kTable,
kTableFromTbl, // Hyrise file format kTableFromTbl // Hyrise file format
}; };
CreateStatement(CreateType type) : CreateStatement(CreateType type) :
SQLStatement(kStmtCreate), SQLStatement(kStmtCreate),
type(type), type(type),
if_not_exists(false), ifNotExists(false),
columns(NULL), filePath(NULL),
file_path(NULL), tableName(NULL),
table_name(NULL) {}; columns(NULL) {};
virtual ~CreateStatement() { virtual ~CreateStatement() {
delete columns; delete columns;
delete file_path; delete filePath;
delete table_name; delete tableName;
} }
CreateType type; CreateType type;
bool if_not_exists;
bool ifNotExists;
const char* filePath;
const char* tableName;
std::vector<ColumnDefinition*>* columns; std::vector<ColumnDefinition*>* columns;
const char* file_path;
const char* table_name;
}; };
} // namespace hsql } // namespace hsql
#endif #endif

View File

@ -4,31 +4,26 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct DeleteStatement * Represents SQL Delete statements.
* @brief Represents "DELETE FROM students WHERE grade > 3.0" * Example: "DELETE FROM students WHERE grade > 3.0"
* *
* If expr == NULL => delete all rows (truncate) * Note: if (expr == NULL) => delete all rows (truncate)
*/ */
struct DeleteStatement : SQLStatement { struct DeleteStatement : SQLStatement {
DeleteStatement() : DeleteStatement() :
SQLStatement(kStmtDelete), SQLStatement(kStmtDelete),
table_name(NULL), tableName(NULL),
expr(NULL) {}; expr(NULL) {};
virtual ~DeleteStatement() { virtual ~DeleteStatement() {
delete table_name; delete tableName;
delete expr; delete expr;
} }
char* tableName;
char* table_name;
Expr* expr; Expr* expr;
}; };
} // namespace hsql } // namespace hsql
#endif #endif

View File

@ -4,11 +4,9 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct DropStatement * Represents SQL Delete statements.
* @brief Represents "DROP TABLE" * Example "DROP TABLE students;"
*/ */
struct DropStatement : SQLStatement { struct DropStatement : SQLStatement {
enum EntityType { enum EntityType {
@ -19,7 +17,6 @@ struct DropStatement : SQLStatement {
kPreparedStatement kPreparedStatement
}; };
DropStatement(EntityType type) : DropStatement(EntityType type) :
SQLStatement(kStmtDrop), SQLStatement(kStmtDrop),
type(type), type(type),
@ -29,14 +26,9 @@ struct DropStatement : SQLStatement {
delete name; delete name;
} }
EntityType type; EntityType type;
const char* name; const char* name;
}; };
} // namespace hsql } // namespace hsql
#endif #endif

View File

@ -4,11 +4,9 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct ExecuteStatement * Represents SQL Execute statements.
* @brief Represents "EXECUTE ins_prep(100, "test", 2.3);" * Example: "EXECUTE ins_prep(100, "test", 2.3);"
*/ */
struct ExecuteStatement : SQLStatement { struct ExecuteStatement : SQLStatement {
ExecuteStatement() : ExecuteStatement() :
@ -25,8 +23,5 @@ struct ExecuteStatement : SQLStatement {
std::vector<Expr*>* parameters; std::vector<Expr*>* parameters;
}; };
} // namsepace hsql } // namsepace hsql
#endif #endif

View File

@ -26,8 +26,7 @@ typedef enum {
typedef struct Expr Expr; typedef struct Expr Expr;
/** /**
* @class Expr * Represents SQL expressions (i.e. literals, operators, column_refs)
* @brief Represents SQL expressions (i.e. literals, operators, column_refs)
* *
* TODO: When destructing a placeholder expression, we might need to alter the placeholder_list * TODO: When destructing a placeholder expression, we might need to alter the placeholder_list
*/ */
@ -88,16 +87,28 @@ struct Expr {
/** /**
* Convenience accessor methods * Convenience accessor methods
*/ */
inline bool isType(ExprType e_type) { return e_type == type; } inline bool isType(ExprType e_type) {
inline bool isLiteral() { return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder); } return e_type == type;
inline bool hasAlias() { return alias != NULL; } }
inline bool hasTable() { return table != NULL; } inline bool isLiteral() {
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
}
inline bool hasAlias() {
return alias != NULL;
}
inline bool hasTable() {
return table != NULL;
}
inline char* getName() { inline char* getName() {
if (alias != NULL) return alias; if (alias != NULL) return alias;
else return name; else return name;
} }
inline bool isSimpleOp() { return op_type == SIMPLE_OP; } inline bool isSimpleOp() {
inline bool isSimpleOp(char op) { return isSimpleOp() && op_char == op; } return op_type == SIMPLE_OP;
}
inline bool isSimpleOp(char op) {
return isSimpleOp() && op_char == op;
}
/** /**

View File

@ -4,13 +4,8 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct ImportStatement * Represents SQL Import statements.
* @brief Represents "IMPORT"
*/ */
struct ImportStatement : SQLStatement { struct ImportStatement : SQLStatement {
enum ImportType { enum ImportType {
@ -18,26 +13,22 @@ struct ImportStatement : SQLStatement {
kImportTbl, // Hyrise file format kImportTbl, // Hyrise file format
}; };
ImportStatement(ImportType type) : ImportStatement(ImportType type) :
SQLStatement(kStmtImport), SQLStatement(kStmtImport),
type(type), type(type),
file_path(NULL), filePath(NULL),
table_name(NULL) {}; tableName(NULL) {};
virtual ~ImportStatement() { virtual ~ImportStatement() {
delete file_path; delete filePath;
delete table_name; delete tableName;
} }
ImportType type; ImportType type;
const char* file_path; const char* filePath;
const char* table_name; const char* tableName;
}; };
} // namespace hsql } // namespace hsql

View File

@ -5,11 +5,9 @@
#include "SelectStatement.h" #include "SelectStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct InsertStatement * Represents SQL Insert statements.
* @brief Represents "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)" * Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
*/ */
struct InsertStatement : SQLStatement { struct InsertStatement : SQLStatement {
enum InsertType { enum InsertType {
@ -20,27 +18,24 @@ struct InsertStatement : SQLStatement {
InsertStatement(InsertType type) : InsertStatement(InsertType type) :
SQLStatement(kStmtInsert), SQLStatement(kStmtInsert),
type(type), type(type),
table_name(NULL), tableName(NULL),
columns(NULL), columns(NULL),
values(NULL), values(NULL),
select(NULL) {} select(NULL) {}
virtual ~InsertStatement() { virtual ~InsertStatement() {
delete table_name; delete tableName;
delete columns; delete columns;
delete values; delete values;
delete select; delete select;
} }
InsertType type; InsertType type;
const char* table_name; const char* tableName;
std::vector<char*>* columns; std::vector<char*>* columns;
std::vector<Expr*>* values; std::vector<Expr*>* values;
SelectStatement* select; SelectStatement* select;
}; };
} // namsepace hsql } // namsepace hsql
#endif #endif

View File

@ -1,16 +1,15 @@
#ifndef __PREPARE_STATEMENT_H__ #ifndef __PREPARE_STATEMENT_H__
#define __PREPARE_STATEMENT_H__ #define __PREPARE_STATEMENT_H__
#include "../SQLParserResult.h"
#include "SQLStatement.h" #include "SQLStatement.h"
#include "SelectStatement.h" #include "SelectStatement.h"
#include <algorithm> #include <algorithm>
namespace hsql { namespace hsql {
/** /**
* @struct PrepareStatement * Represents SQL Prepare statements.
* @brief Represents "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?" * Example: "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
*/ */
struct PrepareStatement : SQLStatement { struct PrepareStatement : SQLStatement {
PrepareStatement() : PrepareStatement() :
@ -24,10 +23,10 @@ struct PrepareStatement : SQLStatement {
} }
/** /**
* @param vector of placeholders that the parser found
*
* When setting the placeholders we need to make sure that they are in the correct order. * When setting the placeholders we need to make sure that they are in the correct order.
* To ensure that, during parsing we store the character position use that to sort the list here. * To ensure that, during parsing we store the character position use that to sort the list here.
*
* @param vector of placeholders that the parser found
*/ */
void setPlaceholders(std::vector<void*> ph) { void setPlaceholders(std::vector<void*> ph) {
for (void* e : ph) { for (void* e : ph) {
@ -42,12 +41,9 @@ struct PrepareStatement : SQLStatement {
} }
const char* name; const char* name;
SQLStatementList* query; SQLParserResult* query;
std::vector<Expr*> placeholders; std::vector<Expr*> placeholders;
}; };
} // namsepace hsql } // namsepace hsql
#endif #endif

View File

@ -1,18 +1,12 @@
/* #ifndef __SQLSTATEMENT_H__
* SQLStatement.h #define __SQLSTATEMENT_H__
* Definition of the structure used to build the syntax tree.
*/
#ifndef __STATEMENT_H__
#define __STATEMENT_H__
#include "Expr.h" #include "Expr.h"
#include <vector> #include <vector>
namespace hsql { namespace hsql {
typedef enum { typedef enum {
kStmtError, // Unused kStmtError, // unused
kStmtSelect, kStmtSelect,
kStmtImport, kStmtImport,
kStmtInsert, kStmtInsert,
@ -27,10 +21,8 @@ typedef enum {
kStmtAlter kStmtAlter
} StatementType; } StatementType;
/** /**
* @struct SQLStatement * Base struct for every SQL statement
* @brief Base class for every SQLStatement
*/ */
struct SQLStatement { struct SQLStatement {
SQLStatement(StatementType type) : SQLStatement(StatementType type) :
@ -38,49 +30,13 @@ struct SQLStatement {
virtual ~SQLStatement() {} virtual ~SQLStatement() {}
virtual StatementType type() { return _type; } virtual StatementType type() {
return _type;
}
private: private:
StatementType _type; StatementType _type;
}; };
/**
* @struct SQLStatementList
* @brief Represents the result of the SQLParser. If parsing was successful it is a list of SQLStatement.
*/
struct SQLStatementList {
public:
SQLStatementList() :
isValid(true),
parser_msg(NULL) {};
SQLStatementList(SQLStatement* stmt) :
isValid(true),
parser_msg(NULL) {
addStatement(stmt);
};
virtual ~SQLStatementList() {
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
delete *it;
}
delete parser_msg;
}
void addStatement(SQLStatement* stmt) { statements.push_back(stmt); }
SQLStatement* getStatement(int id) { return statements[id]; }
size_t numStatements() { return statements.size(); }
std::vector<SQLStatement*> statements;
bool isValid;
const char* parser_msg;
int error_line;
int error_col;
};
} // namespace hsql } // namespace hsql
#endif // __SQLSTATEMENT_H__
#endif // __STATEMENT_H__

View File

@ -6,20 +6,15 @@
#include "Table.h" #include "Table.h"
namespace hsql { namespace hsql {
/**
* @struct OrderDescription
* @brief Description of the order by clause within a select statement
*
* TODO: hold multiple expressions to be sorted by
*/
typedef enum { typedef enum {
kOrderAsc, kOrderAsc,
kOrderDesc kOrderDesc
} OrderType; } OrderType;
/**
* Description of the order by clause within a select statement
* TODO: hold multiple expressions to be sorted by
*/
struct OrderDescription { struct OrderDescription {
OrderDescription(OrderType type, Expr* expr) : OrderDescription(OrderType type, Expr* expr) :
type(type), type(type),
@ -33,12 +28,12 @@ struct OrderDescription {
Expr* expr; Expr* expr;
}; };
/**
* @struct LimitDescription
* @brief Description of the limit clause within a select statement
*/
const int64_t kNoLimit = -1; const int64_t kNoLimit = -1;
const int64_t kNoOffset = -1; const int64_t kNoOffset = -1;
/**
* Description of the limit clause within a select statement
*/
struct LimitDescription { struct LimitDescription {
LimitDescription(int64_t limit, int64_t offset) : LimitDescription(int64_t limit, int64_t offset) :
limit(limit), limit(limit),
@ -49,7 +44,7 @@ struct LimitDescription {
}; };
/** /**
* @struct GroupByDescription * Description of the group-by clause within a select statement
*/ */
struct GroupByDescription { struct GroupByDescription {
GroupByDescription() : GroupByDescription() :
@ -66,43 +61,40 @@ struct GroupByDescription {
}; };
/** /**
* @struct SelectStatement * Representation of a full SQL select statement.
* @brief Representation of a full select statement.
*
* TODO: add union_order and union_limit * TODO: add union_order and union_limit
*/ */
struct SelectStatement : SQLStatement { struct SelectStatement : SQLStatement {
SelectStatement() : SelectStatement() :
SQLStatement(kStmtSelect), SQLStatement(kStmtSelect),
from_table(NULL), fromTable(NULL),
select_list(NULL), selectDistinct(false),
where_clause(NULL), selectList(NULL),
group_by(NULL), whereClause(NULL),
union_select(NULL), groupBy(NULL),
unionSelect(NULL),
order(NULL), order(NULL),
limit(NULL) {}; limit(NULL) {};
virtual ~SelectStatement() { virtual ~SelectStatement() {
delete from_table; delete fromTable;
delete select_list; delete selectList;
delete where_clause; delete whereClause;
delete group_by; delete groupBy;
delete order; delete order;
delete limit; delete limit;
} }
TableRef* from_table; TableRef* fromTable;
bool select_distinct; bool selectDistinct;
std::vector<Expr*>* select_list; std::vector<Expr*>* selectList;
Expr* where_clause; Expr* whereClause;
GroupByDescription* group_by; GroupByDescription* groupBy;
SelectStatement* union_select; SelectStatement* unionSelect;
OrderDescription* order; OrderDescription* order;
LimitDescription* limit; LimitDescription* limit;
}; };
} // namespace hsql } // namespace hsql
#endif #endif

View File

@ -54,7 +54,9 @@ struct TableRef {
/** /**
* Convenience accessor methods * Convenience accessor methods
*/ */
inline bool hasSchema() { return schema != NULL; } inline bool hasSchema() {
return schema != NULL;
}
inline char* getName() { inline char* getName() {
if (alias != NULL) return alias; if (alias != NULL) return alias;

View File

@ -4,21 +4,16 @@
#include "SQLStatement.h" #include "SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* @struct UpdateClause * Represents "column = value" expressions
* @brief Represents "column = value" expressions
*/ */
struct UpdateClause { struct UpdateClause {
char* column; char* column;
Expr* value; Expr* value;
}; };
/** /**
* @struct UpdateStatement * Represents SQL Update statements.
* @brief Represents "UPDATE"
*/ */
struct UpdateStatement : SQLStatement { struct UpdateStatement : SQLStatement {
UpdateStatement() : UpdateStatement() :
@ -39,7 +34,5 @@ struct UpdateStatement : SQLStatement {
Expr* where; Expr* where;
}; };
} // namsepace hsql } // namsepace hsql
#endif #endif

14
src/sql/statements.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __STATEMENTS_H__
#define __STATEMENTS_H__
#include "SelectStatement.h"
#include "ImportStatement.h"
#include "CreateStatement.h"
#include "InsertStatement.h"
#include "UpdateStatement.h"
#include "DeleteStatement.h"
#include "DropStatement.h"
#include "PrepareStatement.h"
#include "ExecuteStatement.h"
#endif // __STATEMENTS_H__

View File

@ -5,138 +5,183 @@
namespace hsql { namespace hsql {
void printOperatorExpression(Expr* expr, uint num_indent); void printOperatorExpression(Expr* expr, uint numIndent);
std::string indent(uint num_indent) { return std::string(num_indent, '\t'); } std::string indent(uint numIndent) {
void inprint(int64_t val, uint num_indent) { printf("%s%lld \n", indent(num_indent).c_str(), val); } return std::string(numIndent, '\t');
void inprint(float val, uint num_indent) { printf("%s%f\n", indent(num_indent).c_str(), val); } }
void inprint(const char* val, uint num_indent) { printf("%s%s\n", indent(num_indent).c_str(), val); } void inprint(int64_t val, uint numIndent) {
void inprint(const char* val, const char* val2, uint num_indent) { printf("%s%s->%s\n", indent(num_indent).c_str(), val, val2); } printf("%s%ld \n", indent(numIndent).c_str(), val);
void inprintC(char val, uint num_indent) { printf("%s%c\n", indent(num_indent).c_str(), val); } }
void inprintU(uint64_t val, uint num_indent) { printf("%s%llu\n", indent(num_indent).c_str(), val); } void inprint(float val, uint numIndent) {
printf("%s%f\n", indent(numIndent).c_str(), val);
}
void inprint(const char* val, uint numIndent) {
printf("%s%s\n", indent(numIndent).c_str(), val);
}
void inprint(const char* val, const char* val2, uint numIndent) {
printf("%s%s->%s\n", indent(numIndent).c_str(), val, val2);
}
void inprintC(char val, uint numIndent) {
printf("%s%c\n", indent(numIndent).c_str(), val);
}
void inprintU(uint64_t val, uint numIndent) {
printf("%s%lu\n", indent(numIndent).c_str(), val);
}
void printTableRefInfo(TableRef* table, uint num_indent) { void printTableRefInfo(TableRef* table, uint numIndent) {
switch (table->type) { switch (table->type) {
case kTableName: case kTableName:
inprint(table->name, num_indent); inprint(table->name, numIndent);
break; break;
case kTableSelect: case kTableSelect:
printSelectStatementInfo(table->select, num_indent); printSelectStatementInfo(table->select, numIndent);
break; break;
case kTableJoin: case kTableJoin:
inprint("Join Table", num_indent); inprint("Join Table", numIndent);
inprint("Left", num_indent+1); inprint("Left", numIndent+1);
printTableRefInfo(table->join->left, num_indent+2); printTableRefInfo(table->join->left, numIndent+2);
inprint("Right", num_indent+1); inprint("Right", numIndent+1);
printTableRefInfo(table->join->right, num_indent+2); printTableRefInfo(table->join->right, numIndent+2);
inprint("Join Condition", num_indent+1); inprint("Join Condition", numIndent+1);
printExpression(table->join->condition, num_indent+2); printExpression(table->join->condition, numIndent+2);
break; break;
case kTableCrossProduct: case kTableCrossProduct:
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent); for (TableRef* tbl : *table->list) printTableRefInfo(tbl, numIndent);
break; break;
} }
if (table->alias != NULL) { if (table->alias != NULL) {
inprint("Alias", num_indent+1); inprint("Alias", numIndent+1);
inprint(table->alias, num_indent+2); inprint(table->alias, numIndent+2);
} }
} }
void printOperatorExpression(Expr* expr, uint num_indent) { void printOperatorExpression(Expr* expr, uint numIndent) {
if (expr == NULL) { inprint("null", num_indent); return; } if (expr == NULL) {
inprint("null", numIndent);
return;
}
switch (expr->op_type) { switch (expr->op_type) {
case Expr::SIMPLE_OP: inprintC(expr->op_char, num_indent); break; case Expr::SIMPLE_OP:
case Expr::AND: inprint("AND", num_indent); break; inprintC(expr->op_char, numIndent);
case Expr::OR: inprint("OR", num_indent); break; break;
case Expr::NOT: inprint("NOT", num_indent); break; case Expr::AND:
default: inprintU(expr->op_type, num_indent); break; inprint("AND", numIndent);
break;
case Expr::OR:
inprint("OR", numIndent);
break;
case Expr::NOT:
inprint("NOT", numIndent);
break;
default:
inprintU(expr->op_type, numIndent);
break;
} }
printExpression(expr->expr, num_indent+1); printExpression(expr->expr, numIndent+1);
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1); if (expr->expr2 != NULL) printExpression(expr->expr2, numIndent+1);
} }
void printExpression(Expr* expr, uint num_indent) { void printExpression(Expr* expr, uint numIndent) {
switch (expr->type) { switch (expr->type) {
case kExprStar: inprint("*", num_indent); break; case kExprStar:
case kExprColumnRef: inprint(expr->name, num_indent); break; inprint("*", numIndent);
// case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break; break;
case kExprLiteralFloat: inprint(expr->fval, num_indent); break; case kExprColumnRef:
case kExprLiteralInt: inprint(expr->ival, num_indent); break; inprint(expr->name, numIndent);
case kExprLiteralString: inprint(expr->name, num_indent); break; break;
case kExprFunctionRef: inprint(expr->name, num_indent); inprint(expr->expr->name, num_indent+1); break; // case kExprTableColumnRef: inprint(expr->table, expr->name, numIndent); break;
case kExprOperator: printOperatorExpression(expr, num_indent); break; case kExprLiteralFloat:
default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return; inprint(expr->fval, numIndent);
break;
case kExprLiteralInt:
inprint(expr->ival, numIndent);
break;
case kExprLiteralString:
inprint(expr->name, numIndent);
break;
case kExprFunctionRef:
inprint(expr->name, numIndent);
inprint(expr->expr->name, numIndent+1);
break;
case kExprOperator:
printOperatorExpression(expr, numIndent);
break;
default:
fprintf(stderr, "Unrecognized expression type %d\n", expr->type);
return;
} }
if (expr->alias != NULL) { if (expr->alias != NULL) {
inprint("Alias", num_indent+1); inprint(expr->alias, num_indent+2); inprint("Alias", numIndent+1);
inprint(expr->alias, numIndent+2);
} }
} }
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) { void printSelectStatementInfo(SelectStatement* stmt, uint numIndent) {
inprint("SelectStatement", num_indent); inprint("SelectStatement", numIndent);
inprint("Fields:", num_indent+1); inprint("Fields:", numIndent+1);
for (Expr* expr : *stmt->select_list) printExpression(expr, num_indent+2); for (Expr* expr : *stmt->selectList) printExpression(expr, numIndent+2);
inprint("Sources:", num_indent+1); inprint("Sources:", numIndent+1);
printTableRefInfo(stmt->from_table, num_indent+2); printTableRefInfo(stmt->fromTable, numIndent+2);
if (stmt->where_clause != NULL) { if (stmt->whereClause != NULL) {
inprint("Search Conditions:", num_indent+1); inprint("Search Conditions:", numIndent+1);
printExpression(stmt->where_clause, num_indent+2); printExpression(stmt->whereClause, numIndent+2);
} }
if (stmt->union_select != NULL) { if (stmt->unionSelect != NULL) {
inprint("Union:", num_indent+1); inprint("Union:", numIndent+1);
printSelectStatementInfo(stmt->union_select, num_indent+2); printSelectStatementInfo(stmt->unionSelect, numIndent+2);
} }
if (stmt->order != NULL) { if (stmt->order != NULL) {
inprint("OrderBy:", num_indent+1); inprint("OrderBy:", numIndent+1);
printExpression(stmt->order->expr, num_indent+2); printExpression(stmt->order->expr, numIndent+2);
if (stmt->order->type == kOrderAsc) inprint("ascending", num_indent+2); if (stmt->order->type == kOrderAsc) inprint("ascending", numIndent+2);
else inprint("descending", num_indent+2); else inprint("descending", numIndent+2);
} }
if (stmt->limit != NULL) { if (stmt->limit != NULL) {
inprint("Limit:", num_indent+1); inprint("Limit:", numIndent+1);
inprint(stmt->limit->limit, num_indent+2); inprint(stmt->limit->limit, numIndent+2);
} }
} }
void printImportStatementInfo(ImportStatement* stmt, uint num_indent) { void printImportStatementInfo(ImportStatement* stmt, uint numIndent) {
inprint("ImportStatment", num_indent); inprint("ImportStatment", numIndent);
inprint(stmt->file_path, num_indent+1); inprint(stmt->filePath, numIndent+1);
inprint(stmt->table_name, num_indent+1); inprint(stmt->tableName, numIndent+1);
} }
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent) { void printCreateStatementInfo(CreateStatement* stmt, uint numIndent) {
inprint("CreateStatment", num_indent); inprint("CreateStatment", numIndent);
inprint(stmt->table_name, num_indent+1); inprint(stmt->tableName, numIndent+1);
inprint(stmt->file_path, num_indent+1); inprint(stmt->filePath, numIndent+1);
} }
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent) { void printInsertStatementInfo(InsertStatement* stmt, uint numIndent) {
inprint("InsertStatment", num_indent); inprint("InsertStatment", numIndent);
inprint(stmt->table_name, num_indent+1); inprint(stmt->tableName, numIndent+1);
if (stmt->columns != NULL) { if (stmt->columns != NULL) {
inprint("Columns", num_indent+1); inprint("Columns", numIndent+1);
for (char* col_name : *stmt->columns) { for (char* col_name : *stmt->columns) {
inprint(col_name, num_indent+2); inprint(col_name, numIndent+2);
} }
} }
switch (stmt->type) { switch (stmt->type) {
case InsertStatement::kInsertValues: case InsertStatement::kInsertValues:
inprint("Values", num_indent+1); inprint("Values", numIndent+1);
for (Expr* expr : *stmt->values) { for (Expr* expr : *stmt->values) {
printExpression(expr, num_indent+2); printExpression(expr, numIndent+2);
} }
break; break;
case InsertStatement::kInsertSelect: case InsertStatement::kInsertSelect:
printSelectStatementInfo(stmt->select, num_indent+1); printSelectStatementInfo(stmt->select, numIndent+1);
break; break;
} }
} }

View File

@ -1,9 +1,7 @@
#ifndef __SQLHELPER_H__ #ifndef __SQLHELPER_H__
#define __SQLHELPER_H__ #define __SQLHELPER_H__
#include "sql/statements.h"
#include "sqltypes.h"
namespace hsql { namespace hsql {

View File

@ -1,16 +0,0 @@
#ifndef __SQLLIB_H__
#define __SQLLIB_H__
typedef unsigned int uint;
#include "sql/SelectStatement.h"
#include "sql/ImportStatement.h"
#include "sql/CreateStatement.h"
#include "sql/InsertStatement.h"
#include "sql/UpdateStatement.h"
#include "sql/DeleteStatement.h"
#include "sql/DropStatement.h"
#include "sql/PrepareStatement.h"
#include "sql/ExecuteStatement.h"
#endif

View File

@ -2,21 +2,21 @@
#define __HELPER_H__ #define __HELPER_H__
#define TEST_PARSE_SQL_QUERY(query, output_var, num_statements) \ #define TEST_PARSE_SQL_QUERY(query, outputVar, numStatements) \
SQLStatementList* output_var = SQLParser::parseSQLString(query); \ SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
ASSERT(output_var->isValid); \ ASSERT(outputVar->isValid); \
ASSERT_EQ(output_var->numStatements(), num_statements); ASSERT_EQ(outputVar->size(), numStatements);
#define TEST_PARSE_SINGLE_SQL(query, stmt_type, stmt_class, output_var) \ #define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, outputVar) \
TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \ TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmt_type); \ ASSERT_EQ(stmt_list->getStatement(0)->type(), stmtType); \
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(0); stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(0);
#define TEST_CAST_STMT(stmt_list, stmt_index, stmt_type, stmt_class, output_var) \ #define TEST_CAST_STMT(stmt_list, stmt_index, stmtType, stmtClass, outputVar) \
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmt_type); \ ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmtType); \
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(stmt_index); stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(stmt_index);
#endif #endif

View File

@ -9,16 +9,16 @@ using namespace hsql;
TEST(SelectTest) { TEST(SelectTest) {
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt); TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt);
ASSERT_NULL(stmt->where_clause); ASSERT_NULL(stmt->whereClause);
ASSERT_NULL(stmt->group_by); ASSERT_NULL(stmt->groupBy);
} }
TEST(SelectHavingTest) { TEST(SelectHavingTest) {
TEST_PARSE_SINGLE_SQL("SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0", kStmtSelect, SelectStatement, stmt); TEST_PARSE_SINGLE_SQL("SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0", kStmtSelect, SelectStatement, stmt);
ASSERT_FALSE(stmt->select_distinct); ASSERT_FALSE(stmt->selectDistinct);
GroupByDescription* group = stmt->group_by; GroupByDescription* group = stmt->groupBy;
ASSERT_NOTNULL(group); ASSERT_NOTNULL(group);
ASSERT_EQ(group->columns->size(), 1); ASSERT_EQ(group->columns->size(), 1);
ASSERT(group->having->isSimpleOp('<')); ASSERT(group->having->isSimpleOp('<'));
@ -30,17 +30,17 @@ TEST(SelectHavingTest) {
TEST(SelectDistinctTest) { TEST(SelectDistinctTest) {
TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt); TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt);
ASSERT(stmt->select_distinct); ASSERT(stmt->selectDistinct);
ASSERT_NULL(stmt->where_clause); ASSERT_NULL(stmt->whereClause);
} }
TEST(SelectGroupDistinctTest) { TEST(SelectGroupDistinctTest) {
TEST_PARSE_SINGLE_SQL("SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;", kStmtSelect, SelectStatement, stmt); TEST_PARSE_SINGLE_SQL("SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;", kStmtSelect, SelectStatement, stmt);
ASSERT_FALSE(stmt->select_distinct); ASSERT_FALSE(stmt->selectDistinct);
ASSERT_EQ(stmt->select_list->size(), 3); ASSERT_EQ(stmt->selectList->size(), 3);
ASSERT(!stmt->select_list->at(1)->distinct); ASSERT(!stmt->selectList->at(1)->distinct);
ASSERT(stmt->select_list->at(2)->distinct); ASSERT(stmt->selectList->at(2)->distinct);
} }

View File

@ -7,9 +7,9 @@ class TestsManager {
// http://www.parashift.com/c++-faq-lite/static-init-order.html // http://www.parashift.com/c++-faq-lite/static-init-order.html
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html // http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
public: public:
static std::vector<std::string>& test_names() { static std::vector<std::string>& testNames() {
static std::vector<std::string>* test_names = new std::vector<std::string>; static std::vector<std::string>* _testNames = new std::vector<std::string>;
return *test_names; return *_testNames;
} }
static std::vector<void (*)(void)>& tests() { static std::vector<void (*)(void)>& tests() {
@ -22,34 +22,38 @@ public:
int AddTest(void (*foo)(void), std::string name) { int AddTest(void (*foo)(void), std::string name) {
TestsManager::tests().push_back(foo); TestsManager::tests().push_back(foo);
TestsManager::test_names().push_back(name); TestsManager::testNames().push_back(name);
return 0; return 0;
} }
void RunTests() { size_t RunTests() {
size_t num_failed = 0; size_t numFailed = 0;
for (size_t i = 0; i < TestsManager::tests().size(); ++i) { for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::test_names()[i].c_str()); printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::testNames()[i].c_str());
try { try {
// Run test // Run test
(*TestsManager::tests()[i])(); (*TestsManager::tests()[i])();
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::test_names()[i].c_str()); printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::testNames()[i].c_str());
} catch (AssertionFailedException& e) { } catch (AssertionFailedException& e) {
printf("\033[1;31m{ failed} %s\n", TestsManager::test_names()[i].c_str()); printf("\033[1;31m{ failed} %s\n", TestsManager::testNames()[i].c_str());
printf("\tAssertion failed: %s\n\033[0m", e.what()); printf("\tAssertion failed: %s\n\033[0m", e.what());
num_failed++; numFailed++;
} }
} }
return numFailed;
} }
int main() { int main() {
RunTests(); size_t numFailed = RunTests();
if (numFailed == 0) {
return 0; return 0;
} else {
return -1;
}
} }

View File

@ -44,11 +44,6 @@ protected:
std::string _msg; std::string _msg;
}; };
int AddTest(void (*foo)(void), std::string name); int AddTest(void (*foo)(void), std::string name);
#endif #endif

View File

@ -33,17 +33,17 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
bool expect_false = false; bool expectFalse = false;
bool use_file = false; bool useFile = false;
std::string file_path = ""; std::string filePath = "";
// Parse command line arguments // Parse command line arguments
int i = 1; int i = 1;
for (; i < argc; ++i) { for (; i < argc; ++i) {
if (STREQ(argv[i], "--false")) expect_false = true; if (STREQ(argv[i], "--false")) expectFalse = true;
else if (STREQ(argv[i], "-f")) { else if (STREQ(argv[i], "-f")) {
use_file = true; useFile = true;
file_path = argv[++i]; filePath = argv[++i];
} else { } else {
break; break;
} }
@ -52,44 +52,43 @@ int main(int argc, char *argv[]) {
// Read list of queries for this rest // Read list of queries for this rest
std::vector<std::string> queries; std::vector<std::string> queries;
if (use_file) { if (useFile) {
queries = readlines(file_path); queries = readlines(filePath);
} else { } else {
for (; i < argc; ++i) queries.push_back(argv[i]); for (; i < argc; ++i) queries.push_back(argv[i]);
} }
// Execute queries // Execute queries
int num_failed = 0; int numFailed = 0;
for (std::string sql : queries) { for (std::string sql : queries) {
// Measuring the parsing time // Measuring the parsing time
std::chrono::time_point<std::chrono::system_clock> start, end; std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now(); start = std::chrono::system_clock::now();
// Parsing // Parsing
SQLStatementList* stmt_list = SQLParser::parseSQLString(sql.c_str()); SQLParserResult* stmt_list = SQLParser::parseSQLString(sql.c_str());
end = std::chrono::system_clock::now(); end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start; std::chrono::duration<double> elapsed_seconds = end-start;
double us = elapsed_seconds.count() * 1000 * 1000; double us = elapsed_seconds.count() * 1000 * 1000;
if (expect_false == stmt_list->isValid) { if (expectFalse == stmt_list->isValid) {
printf("\033[0;31m{ failed}\033[0m\n"); printf("\033[0;31m{ failed}\033[0m\n");
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", stmt_list->parser_msg, stmt_list->error_line, stmt_list->error_col); printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", stmt_list->errorMsg, stmt_list->errorLine, stmt_list->errorColumn);
printf("\t%s\n", sql.c_str()); printf("\t%s\n", sql.c_str());
num_failed++; numFailed++;
} else { } else {
// TODO: indicate whether expect_false was set // TODO: indicate whether expectFalse was set
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str()); printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
} }
} }
if (num_failed == 0) { if (numFailed == 0) {
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size()); 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", num_failed, queries.size());
}
return 0; return 0;
} else {
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
return -1;
}
} }

View File

@ -11,13 +11,13 @@ using namespace hsql;
TEST(DeleteStatementTest) { TEST(DeleteStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
ASSERT(stmt_list->isValid); ASSERT(result->isValid);
ASSERT_EQ(stmt_list->numStatements(), 1); ASSERT_EQ(result->size(), 1);
ASSERT(stmt_list->getStatement(0)->type() == kStmtDelete); ASSERT(result->getStatement(0)->type() == kStmtDelete);
DeleteStatement* stmt = (DeleteStatement*) stmt_list->getStatement(0); DeleteStatement* stmt = (DeleteStatement*) result->getStatement(0);
ASSERT_STREQ(stmt->table_name, "students"); ASSERT_STREQ(stmt->tableName, "students");
ASSERT_NOTNULL(stmt->expr); ASSERT_NOTNULL(stmt->expr);
ASSERT(stmt->expr->isType(kExprOperator)); ASSERT(stmt->expr->isType(kExprOperator));
ASSERT_STREQ(stmt->expr->expr->name, "grade"); ASSERT_STREQ(stmt->expr->expr->name, "grade");
@ -25,14 +25,14 @@ TEST(DeleteStatementTest) {
} }
TEST(CreateStatementTest) { TEST(CreateStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)"); SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
ASSERT(stmt_list->isValid); ASSERT(result->isValid);
ASSERT_EQ(stmt_list->numStatements(), 1); ASSERT_EQ(result->size(), 1);
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtCreate); ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
CreateStatement* stmt = (CreateStatement*) stmt_list->getStatement(0); CreateStatement* stmt = (CreateStatement*) result->getStatement(0);
ASSERT_EQ(stmt->type, CreateStatement::kTable); ASSERT_EQ(stmt->type, CreateStatement::kTable);
ASSERT_STREQ(stmt->table_name, "students"); ASSERT_STREQ(stmt->tableName, "students");
ASSERT_NOTNULL(stmt->columns); ASSERT_NOTNULL(stmt->columns);
ASSERT_EQ(stmt->columns->size(), 4); ASSERT_EQ(stmt->columns->size(), 4);
ASSERT_STREQ(stmt->columns->at(0)->name, "name"); ASSERT_STREQ(stmt->columns->at(0)->name, "name");
@ -47,12 +47,12 @@ TEST(CreateStatementTest) {
TEST(UpdateStatementTest) { TEST(UpdateStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';"); SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
ASSERT(stmt_list->isValid); ASSERT(result->isValid);
ASSERT_EQ(stmt_list->numStatements(), 1); ASSERT_EQ(result->size(), 1);
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtUpdate); ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
UpdateStatement* stmt = (UpdateStatement*) stmt_list->getStatement(0); UpdateStatement* stmt = (UpdateStatement*) result->getStatement(0);
ASSERT_NOTNULL(stmt->table); ASSERT_NOTNULL(stmt->table);
ASSERT_STREQ(stmt->table->name, "students"); ASSERT_STREQ(stmt->table->name, "students");
@ -99,33 +99,33 @@ TEST(PrepareStatementTest) {
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;" "PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
"DEALLOCATE PREPARE stmt;"; "DEALLOCATE PREPARE stmt;";
TEST_PARSE_SQL_QUERY(query, stmt_list, 3); TEST_PARSE_SQL_QUERY(query, result, 3);
TEST_CAST_STMT(stmt_list, 0, kStmtPrepare, PrepareStatement, prep1); TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
TEST_CAST_STMT(stmt_list, 1, kStmtPrepare, PrepareStatement, prep2); TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
TEST_CAST_STMT(stmt_list, 2, kStmtDrop, DropStatement, drop); TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
// Prepare Statement #1 // Prepare Statement #1
ASSERT_STREQ(prep1->name, "test"); ASSERT_STREQ(prep1->name, "test");
ASSERT_EQ(prep1->placeholders.size(), 3); ASSERT_EQ(prep1->placeholders.size(), 3);
ASSERT_EQ(prep1->query->numStatements(), 2); ASSERT_EQ(prep1->query->size(), 2);
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert); TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select); TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
ASSERT(insert->values->at(0)->isType(kExprPlaceholder)); ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
ASSERT(select->select_list->at(0)->isType(kExprPlaceholder)); ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
ASSERT(select->where_clause->expr2->isType(kExprPlaceholder)); ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
// Check IDs of placeholders // Check IDs of placeholders
ASSERT_EQ(insert->values->at(0)->ival, 0); ASSERT_EQ(insert->values->at(0)->ival, 0);
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]); ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
ASSERT_EQ(select->select_list->at(0)->ival, 1); ASSERT_EQ(select->selectList->at(0)->ival, 1);
ASSERT_EQ(select->select_list->at(0), prep1->placeholders[1]); ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
ASSERT_EQ(select->where_clause->expr2->ival, 2); ASSERT_EQ(select->whereClause->expr2->ival, 2);
ASSERT_EQ(select->where_clause->expr2, prep1->placeholders[2]); ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
// Prepare Statement #2 // Prepare Statement #2
ASSERT_STREQ(prep2->name, "stmt"); ASSERT_STREQ(prep2->name, "stmt");

15
test/test.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# has to be executed from the root of the repository
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
RET1=$?
bin/sql_tests
RET2=$?
if [[ $RET1 != 0 ]]; then exit $RET1; fi
if [[ $RET2 != 0 ]]; then exit $RET2; fi
exit 0