Merge pull request #12 from torpedro/api-cleanup
Improve API & formatting. Adds clang support & travis ci
This commit is contained in:
commit
7cfae24503
|
@ -31,3 +31,6 @@ lib-test/
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
*.cpp.orig
|
||||
*.h.orig
|
|
@ -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
|
28
Makefile
28
Makefile
|
@ -9,25 +9,27 @@ LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(S
|
|||
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
||||
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
|
||||
CC = g++
|
||||
CFLAGS = -std=c++11 -Wall -fPIC
|
||||
LIBFLAGS = -shared
|
||||
TARGET = libsqlparser.so
|
||||
INSTALL = /usr/local
|
||||
|
||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11
|
||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++
|
||||
|
||||
all: library
|
||||
|
||||
library: $(TARGET)
|
||||
|
||||
$(TARGET): $(LIBOBJ)
|
||||
$(CC) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ)
|
||||
$(CXX) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ)
|
||||
|
||||
|
||||
%.o: %.cpp $(PARSERFILES)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(SRCPARSER)/bison_parser.cpp: parser
|
||||
$(SRCPARSER)/flex_lexer.cpp: parser
|
||||
|
@ -48,20 +50,26 @@ cleanall: clean cleanparser
|
|||
install:
|
||||
cp $(TARGET) $(INSTALL)/lib/$(TARGET)
|
||||
|
||||
format:
|
||||
astyle --options=astyle.options $(ALLLIB)
|
||||
astyle --options=astyle.options $(ALLTEST)
|
||||
|
||||
############
|
||||
### Test ###
|
||||
############
|
||||
|
||||
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
|
||||
LD_LIBRARY_PATH=./ $(BIN)/sql_grammar_test -f "test/lib/valid_queries.sql"
|
||||
LD_LIBRARY_PATH=./ $(BIN)/sql_tests
|
||||
bash test/test.sh
|
||||
|
||||
# test whete
|
||||
test_install:
|
||||
make -C example/
|
||||
./example/example "SELECT * FROM students WHERE name = 'Max Mustermann';"
|
||||
|
||||
$(BIN)/sql_tests: library
|
||||
@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
|
||||
@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
|
||||
|
|
17
README.md
17
README.md
|
@ -9,18 +9,23 @@ In March 2015 we've also written a short paper outlining discussing some develop
|
|||
|
||||
### 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)
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
### Development
|
||||
|
||||
**Prerequisites:**
|
||||
**Requirements for development:**
|
||||
* gcc 4.8 (or newer)
|
||||
* [bison](https://www.gnu.org/software/bison/) (tested with v3.0.2)
|
||||
* [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.
|
||||
|
||||
|
||||
### Documenation
|
||||
### Resources
|
||||
|
||||
* [Working Syntax Examples](docs/syntax.md)
|
||||
* [Known Issues](docs/issues.md)
|
||||
* [Developer Documentation](docs/documentation.md)
|
||||
* [Integration in Hyrise](docs/integration.md)
|
||||
* [Developer Documentation](docs/dev-docs.md)
|
||||
|
||||
|
||||
### License
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
# indentation
|
||||
--indent=spaces=4
|
||||
--indent-namespaces
|
||||
|
||||
--style=java
|
||||
--style=attach
|
||||
-A2
|
|
@ -1,29 +1,31 @@
|
|||
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/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.
|
||||
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`.
|
||||
|
||||
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:
|
||||
* src/parser/bison_parser.y
|
||||
* src/parser/flex_lexer.l
|
||||
* src/parser/keywordlist_generator.py
|
||||
* src/parser/sql_keywords.txt
|
||||
````
|
||||
src/parser/bison_parser.y
|
||||
src/parser/flex_lexer.l
|
||||
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.
|
||||
|
||||
|
@ -33,7 +35,6 @@ If your defining a new statement, you will need to define your type in the \%uni
|
|||
|
||||
## Implementing Tests
|
||||
|
||||
Related files:
|
||||
* src/sql_tests.cpp
|
||||
All test related files are in `test/`. Take a look to see how tests are implemented.
|
||||
|
||||
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
CC = g++
|
||||
CFLAGS = -std=c++11 -Wall -I../src/ -L../
|
||||
CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../
|
||||
|
||||
all:
|
||||
$(CC) $(CFLAGS) example.cpp -o example -lsqlparser
|
||||
$(CXX) $(CFLAGS) example.cpp -o example -lsqlparser
|
||||
|
||||
|
|
|
@ -16,20 +16,21 @@ int main(int argc, char *argv[]) {
|
|||
std::string query = argv[1];
|
||||
|
||||
// parse a given query
|
||||
hsql::SQLStatementList* result = hsql::SQLParser::parseSQLString(query);
|
||||
hsql::SQLParserResult* result = hsql::SQLParser::parseSQLString(query);
|
||||
|
||||
// check whether the parsing was successful
|
||||
if (result->isValid) {
|
||||
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) {
|
||||
// process the statements...
|
||||
hsql::printStatementInfo(stmt);
|
||||
}
|
||||
} else {
|
||||
printf("Invalid SQL!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
printf("Invalid SQL!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ SQLParser::SQLParser() {
|
|||
}
|
||||
|
||||
|
||||
SQLStatementList* SQLParser::parseSQLString(const char *text) {
|
||||
SQLStatementList* result;
|
||||
SQLParserResult* SQLParser::parseSQLString(const char *text) {
|
||||
SQLParserResult* result = NULL;
|
||||
yyscan_t scanner;
|
||||
YY_BUFFER_STATE state;
|
||||
|
||||
|
@ -37,7 +37,8 @@ SQLStatementList* SQLParser::parseSQLString(const char *text) {
|
|||
return result;
|
||||
}
|
||||
|
||||
SQLStatementList* SQLParser::parseSQLString(const std::string& text) {
|
||||
|
||||
SQLParserResult* SQLParser::parseSQLString(const std::string& text) {
|
||||
return parseSQLString(text.c_str());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
#ifndef __SQLPARSER_H_
|
||||
#define __SQLPARSER_H_
|
||||
|
||||
#include "sqltypes.h"
|
||||
#include "SQLParserResult.h"
|
||||
#include "sql/statements.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
/*!
|
||||
* \mainpage SQLParser (C++)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Main class for parsing SQL strings
|
||||
/**
|
||||
* Main class for parsing SQL strings
|
||||
*/
|
||||
class SQLParser {
|
||||
public:
|
||||
static SQLStatementList* parseSQLString(const char* sql);
|
||||
static SQLStatementList* parseSQLString(const std::string& sql);
|
||||
static SQLParserResult* parseSQLString(const char* sql);
|
||||
static SQLParserResult* parseSQLString(const std::string& sql);
|
||||
|
||||
private:
|
||||
SQLParser();
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -48,9 +48,12 @@
|
|||
extern int hsql_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
#line 43 "bison_parser.y" /* yacc.c:1909 */
|
||||
#line 42 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
// %code requires block
|
||||
|
||||
#include "../sql/statements.h"
|
||||
#include "../SQLParserResult.h"
|
||||
#include "parser_typedef.h"
|
||||
|
||||
// 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. */
|
||||
#ifndef HSQL_TOKENTYPE
|
||||
|
@ -206,7 +209,7 @@ extern int hsql_debug;
|
|||
typedef union HSQL_STYPE HSQL_STYPE;
|
||||
union HSQL_STYPE
|
||||
{
|
||||
#line 99 "bison_parser.y" /* yacc.c:1909 */
|
||||
#line 101 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
double fval;
|
||||
int64_t ival;
|
||||
|
@ -234,7 +237,7 @@ union HSQL_STYPE
|
|||
hsql::GroupByDescription* group_t;
|
||||
hsql::UpdateClause* update_t;
|
||||
|
||||
hsql::SQLStatementList* stmt_list;
|
||||
hsql::SQLParserResult* stmt_list;
|
||||
|
||||
std::vector<char*>* str_vec;
|
||||
std::vector<hsql::TableRef*>* table_vec;
|
||||
|
@ -242,7 +245,7 @@ union HSQL_STYPE
|
|||
std::vector<hsql::UpdateClause*>* update_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_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 */
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
** Section 1: C Declarations
|
||||
*********************************/
|
||||
|
||||
#include "../sqltypes.h"
|
||||
#include "bison_parser.h"
|
||||
#include "flex_lexer.h"
|
||||
|
||||
|
@ -19,13 +18,13 @@
|
|||
|
||||
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->parser_msg = strdup(msg);
|
||||
list->error_line = llocp->first_line;
|
||||
list->error_col = llocp->first_column;
|
||||
list->errorMsg = strdup(msg);
|
||||
list->errorLine = llocp->first_line;
|
||||
list->errorColumn = llocp->first_column;
|
||||
|
||||
*result = list;
|
||||
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
|
||||
%code requires {
|
||||
// %code requires block
|
||||
|
||||
#include "../sql/statements.h"
|
||||
#include "../SQLParserResult.h"
|
||||
#include "parser_typedef.h"
|
||||
|
||||
// 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 }
|
||||
|
||||
// Define additional parameters for yyparse
|
||||
%parse-param { hsql::SQLStatementList** result }
|
||||
%parse-param { hsql::SQLParserResult** result }
|
||||
%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::UpdateClause* update_t;
|
||||
|
||||
hsql::SQLStatementList* stmt_list;
|
||||
hsql::SQLParserResult* stmt_list;
|
||||
|
||||
std::vector<char*>* str_vec;
|
||||
std::vector<hsql::TableRef*>* table_vec;
|
||||
|
@ -231,7 +233,7 @@ input:
|
|||
|
||||
|
||||
statement_list:
|
||||
statement { $$ = new SQLStatementList($1); }
|
||||
statement { $$ = new SQLParserResult($1); }
|
||||
| statement_list ';' statement { $1->addStatement($3); $$ = $1; }
|
||||
;
|
||||
|
||||
|
@ -265,7 +267,7 @@ prepare_statement:
|
|||
PREPARE IDENTIFIER ':' preparable_statement {
|
||||
$$ = new PrepareStatement();
|
||||
$$->name = $2;
|
||||
$$->query = new SQLStatementList($4);
|
||||
$$->query = new SQLParserResult($4);
|
||||
}
|
||||
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
|
||||
$$ = new PrepareStatement();
|
||||
|
@ -293,8 +295,8 @@ execute_statement:
|
|||
import_statement:
|
||||
IMPORT FROM import_file_type FILE file_path INTO table_name {
|
||||
$$ = new ImportStatement((ImportStatement::ImportType) $3);
|
||||
$$->file_path = $5;
|
||||
$$->table_name = $7;
|
||||
$$->filePath = $5;
|
||||
$$->tableName = $7;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -315,14 +317,14 @@ file_path:
|
|||
create_statement:
|
||||
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
|
||||
$$ = new CreateStatement(CreateStatement::kTableFromTbl);
|
||||
$$->if_not_exists = $3;
|
||||
$$->table_name = $4;
|
||||
$$->file_path = $8;
|
||||
$$->ifNotExists = $3;
|
||||
$$->tableName = $4;
|
||||
$$->filePath = $8;
|
||||
}
|
||||
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
|
||||
$$ = new CreateStatement(CreateStatement::kTable);
|
||||
$$->if_not_exists = $3;
|
||||
$$->table_name = $4;
|
||||
$$->ifNotExists = $3;
|
||||
$$->tableName = $4;
|
||||
$$->columns = $6;
|
||||
}
|
||||
;
|
||||
|
@ -376,7 +378,7 @@ drop_statement:
|
|||
delete_statement:
|
||||
DELETE FROM table_name opt_where {
|
||||
$$ = new DeleteStatement();
|
||||
$$->table_name = $3;
|
||||
$$->tableName = $3;
|
||||
$$->expr = $4;
|
||||
}
|
||||
;
|
||||
|
@ -384,7 +386,7 @@ delete_statement:
|
|||
truncate_statement:
|
||||
TRUNCATE table_name {
|
||||
$$ = new DeleteStatement();
|
||||
$$->table_name = $2;
|
||||
$$->tableName = $2;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -396,13 +398,13 @@ truncate_statement:
|
|||
insert_statement:
|
||||
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
|
||||
$$ = new InsertStatement(InsertStatement::kInsertValues);
|
||||
$$->table_name = $3;
|
||||
$$->tableName = $3;
|
||||
$$->columns = $4;
|
||||
$$->values = $7;
|
||||
}
|
||||
| INSERT INTO table_name opt_column_list select_no_paren {
|
||||
$$ = new InsertStatement(InsertStatement::kInsertSelect);
|
||||
$$->table_name = $3;
|
||||
$$->tableName = $3;
|
||||
$$->columns = $4;
|
||||
$$->select = $5;
|
||||
}
|
||||
|
@ -467,7 +469,7 @@ select_no_paren:
|
|||
// TODO: capture type of set_operator
|
||||
// TODO: might overwrite order and limit of first select here
|
||||
$$ = $1;
|
||||
$$->union_select = $3;
|
||||
$$->unionSelect = $3;
|
||||
$$->order = $4;
|
||||
$$->limit = $5;
|
||||
}
|
||||
|
@ -482,11 +484,11 @@ set_operator:
|
|||
select_clause:
|
||||
SELECT opt_distinct select_list from_clause opt_where opt_group {
|
||||
$$ = new SelectStatement();
|
||||
$$->select_distinct = $2;
|
||||
$$->select_list = $3;
|
||||
$$->from_table = $4;
|
||||
$$->where_clause = $5;
|
||||
$$->group_by = $6;
|
||||
$$->selectDistinct = $2;
|
||||
$$->selectList = $3;
|
||||
$$->fromTable = $4;
|
||||
$$->whereClause = $5;
|
||||
$$->groupBy = $6;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
@ -1545,7 +1545,7 @@ static yyconst flex_int16_t yy_chk[3639] =
|
|||
***************************/
|
||||
#line 12 "flex_lexer.l"
|
||||
|
||||
#include "../sqltypes.h"
|
||||
#include "../sql/Expr.h"
|
||||
#include "bison_parser.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
***************************/
|
||||
%{
|
||||
|
||||
#include "../sqltypes.h"
|
||||
#include "../sql/Expr.h"
|
||||
#include "bison_parser.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
/**
|
||||
* @struct ColumnDefinition
|
||||
* @brief Represents definition of a table column
|
||||
* Represents definition of a table column
|
||||
*/
|
||||
struct ColumnDefinition {
|
||||
enum DataType {
|
||||
|
@ -28,41 +26,37 @@ struct ColumnDefinition {
|
|||
DataType type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @struct CreateStatement
|
||||
* @brief Represents "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||
* Represents SQL Create statements.
|
||||
* Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||
*/
|
||||
struct CreateStatement : SQLStatement {
|
||||
enum CreateType {
|
||||
kTable,
|
||||
kTableFromTbl, // Hyrise file format
|
||||
kTableFromTbl // Hyrise file format
|
||||
};
|
||||
|
||||
CreateStatement(CreateType type) :
|
||||
SQLStatement(kStmtCreate),
|
||||
type(type),
|
||||
if_not_exists(false),
|
||||
columns(NULL),
|
||||
file_path(NULL),
|
||||
table_name(NULL) {};
|
||||
ifNotExists(false),
|
||||
filePath(NULL),
|
||||
tableName(NULL),
|
||||
columns(NULL) {};
|
||||
|
||||
virtual ~CreateStatement() {
|
||||
delete columns;
|
||||
delete file_path;
|
||||
delete table_name;
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
|
||||
CreateType type;
|
||||
bool if_not_exists;
|
||||
|
||||
bool ifNotExists;
|
||||
const char* filePath;
|
||||
const char* tableName;
|
||||
std::vector<ColumnDefinition*>* columns;
|
||||
|
||||
const char* file_path;
|
||||
const char* table_name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
|
@ -4,31 +4,26 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct DeleteStatement
|
||||
* @brief Represents "DELETE FROM students WHERE grade > 3.0"
|
||||
* Represents SQL Delete statements.
|
||||
* 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 {
|
||||
DeleteStatement() :
|
||||
SQLStatement(kStmtDelete),
|
||||
table_name(NULL),
|
||||
tableName(NULL),
|
||||
expr(NULL) {};
|
||||
|
||||
virtual ~DeleteStatement() {
|
||||
delete table_name;
|
||||
delete tableName;
|
||||
delete expr;
|
||||
}
|
||||
|
||||
|
||||
char* table_name;
|
||||
char* tableName;
|
||||
Expr* expr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
|
@ -4,11 +4,9 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct DropStatement
|
||||
* @brief Represents "DROP TABLE"
|
||||
* Represents SQL Delete statements.
|
||||
* Example "DROP TABLE students;"
|
||||
*/
|
||||
struct DropStatement : SQLStatement {
|
||||
enum EntityType {
|
||||
|
@ -19,7 +17,6 @@ struct DropStatement : SQLStatement {
|
|||
kPreparedStatement
|
||||
};
|
||||
|
||||
|
||||
DropStatement(EntityType type) :
|
||||
SQLStatement(kStmtDrop),
|
||||
type(type),
|
||||
|
@ -29,14 +26,9 @@ struct DropStatement : SQLStatement {
|
|||
delete name;
|
||||
}
|
||||
|
||||
|
||||
EntityType type;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
|
@ -4,11 +4,9 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct ExecuteStatement
|
||||
* @brief Represents "EXECUTE ins_prep(100, "test", 2.3);"
|
||||
* Represents SQL Execute statements.
|
||||
* Example: "EXECUTE ins_prep(100, "test", 2.3);"
|
||||
*/
|
||||
struct ExecuteStatement : SQLStatement {
|
||||
ExecuteStatement() :
|
||||
|
@ -25,8 +23,5 @@ struct ExecuteStatement : SQLStatement {
|
|||
std::vector<Expr*>* parameters;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namsepace hsql
|
||||
#endif
|
|
@ -26,8 +26,7 @@ typedef enum {
|
|||
typedef struct Expr Expr;
|
||||
|
||||
/**
|
||||
* @class Expr
|
||||
* @brief Represents SQL expressions (i.e. literals, operators, column_refs)
|
||||
* Represents SQL expressions (i.e. literals, operators, column_refs)
|
||||
*
|
||||
* TODO: When destructing a placeholder expression, we might need to alter the placeholder_list
|
||||
*/
|
||||
|
@ -88,16 +87,28 @@ struct Expr {
|
|||
/**
|
||||
* Convenience accessor methods
|
||||
*/
|
||||
inline bool isType(ExprType e_type) { return e_type == type; }
|
||||
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 bool isType(ExprType e_type) {
|
||||
return e_type == type;
|
||||
}
|
||||
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() {
|
||||
if (alias != NULL) return alias;
|
||||
else return name;
|
||||
}
|
||||
inline bool isSimpleOp() { return op_type == SIMPLE_OP; }
|
||||
inline bool isSimpleOp(char op) { return isSimpleOp() && op_char == op; }
|
||||
inline bool isSimpleOp() {
|
||||
return op_type == SIMPLE_OP;
|
||||
}
|
||||
inline bool isSimpleOp(char op) {
|
||||
return isSimpleOp() && op_char == op;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,13 +4,8 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @struct ImportStatement
|
||||
* @brief Represents "IMPORT"
|
||||
* Represents SQL Import statements.
|
||||
*/
|
||||
struct ImportStatement : SQLStatement {
|
||||
enum ImportType {
|
||||
|
@ -18,26 +13,22 @@ struct ImportStatement : SQLStatement {
|
|||
kImportTbl, // Hyrise file format
|
||||
};
|
||||
|
||||
|
||||
ImportStatement(ImportType type) :
|
||||
SQLStatement(kStmtImport),
|
||||
type(type),
|
||||
file_path(NULL),
|
||||
table_name(NULL) {};
|
||||
filePath(NULL),
|
||||
tableName(NULL) {};
|
||||
|
||||
virtual ~ImportStatement() {
|
||||
delete file_path;
|
||||
delete table_name;
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
|
||||
|
||||
ImportType type;
|
||||
const char* file_path;
|
||||
const char* table_name;
|
||||
const char* filePath;
|
||||
const char* tableName;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct InsertStatement
|
||||
* @brief Represents "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
|
||||
* Represents SQL Insert statements.
|
||||
* Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
|
||||
*/
|
||||
struct InsertStatement : SQLStatement {
|
||||
enum InsertType {
|
||||
|
@ -20,27 +18,24 @@ struct InsertStatement : SQLStatement {
|
|||
InsertStatement(InsertType type) :
|
||||
SQLStatement(kStmtInsert),
|
||||
type(type),
|
||||
table_name(NULL),
|
||||
tableName(NULL),
|
||||
columns(NULL),
|
||||
values(NULL),
|
||||
select(NULL) {}
|
||||
|
||||
virtual ~InsertStatement() {
|
||||
delete table_name;
|
||||
delete tableName;
|
||||
delete columns;
|
||||
delete values;
|
||||
delete select;
|
||||
}
|
||||
|
||||
InsertType type;
|
||||
const char* table_name;
|
||||
const char* tableName;
|
||||
std::vector<char*>* columns;
|
||||
std::vector<Expr*>* values;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namsepace hsql
|
||||
#endif
|
|
@ -1,16 +1,15 @@
|
|||
#ifndef __PREPARE_STATEMENT_H__
|
||||
#define __PREPARE_STATEMENT_H__
|
||||
|
||||
#include "../SQLParserResult.h"
|
||||
#include "SQLStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct PrepareStatement
|
||||
* @brief Represents "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
|
||||
* Represents SQL Prepare statements.
|
||||
* Example: "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
|
||||
*/
|
||||
struct PrepareStatement : SQLStatement {
|
||||
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.
|
||||
* 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) {
|
||||
for (void* e : ph) {
|
||||
|
@ -42,12 +41,9 @@ struct PrepareStatement : SQLStatement {
|
|||
}
|
||||
|
||||
const char* name;
|
||||
SQLStatementList* query;
|
||||
SQLParserResult* query;
|
||||
std::vector<Expr*> placeholders;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namsepace hsql
|
||||
#endif
|
|
@ -1,18 +1,12 @@
|
|||
/*
|
||||
* SQLStatement.h
|
||||
* Definition of the structure used to build the syntax tree.
|
||||
*/
|
||||
#ifndef __STATEMENT_H__
|
||||
#define __STATEMENT_H__
|
||||
#ifndef __SQLSTATEMENT_H__
|
||||
#define __SQLSTATEMENT_H__
|
||||
|
||||
#include "Expr.h"
|
||||
#include <vector>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
typedef enum {
|
||||
kStmtError, // Unused
|
||||
kStmtError, // unused
|
||||
kStmtSelect,
|
||||
kStmtImport,
|
||||
kStmtInsert,
|
||||
|
@ -27,10 +21,8 @@ typedef enum {
|
|||
kStmtAlter
|
||||
} StatementType;
|
||||
|
||||
|
||||
/**
|
||||
* @struct SQLStatement
|
||||
* @brief Base class for every SQLStatement
|
||||
* Base struct for every SQL statement
|
||||
*/
|
||||
struct SQLStatement {
|
||||
SQLStatement(StatementType type) :
|
||||
|
@ -38,49 +30,13 @@ struct SQLStatement {
|
|||
|
||||
virtual ~SQLStatement() {}
|
||||
|
||||
virtual StatementType type() { return _type; }
|
||||
virtual StatementType type() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
private:
|
||||
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
|
||||
|
||||
#endif // __STATEMENT_H__
|
||||
#endif // __SQLSTATEMENT_H__
|
||||
|
|
|
@ -6,20 +6,15 @@
|
|||
#include "Table.h"
|
||||
|
||||
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 {
|
||||
kOrderAsc,
|
||||
kOrderDesc
|
||||
} OrderType;
|
||||
|
||||
/**
|
||||
* Description of the order by clause within a select statement
|
||||
* TODO: hold multiple expressions to be sorted by
|
||||
*/
|
||||
struct OrderDescription {
|
||||
OrderDescription(OrderType type, Expr* expr) :
|
||||
type(type),
|
||||
|
@ -33,12 +28,12 @@ struct OrderDescription {
|
|||
Expr* expr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct LimitDescription
|
||||
* @brief Description of the limit clause within a select statement
|
||||
*/
|
||||
const int64_t kNoLimit = -1;
|
||||
const int64_t kNoOffset = -1;
|
||||
|
||||
/**
|
||||
* Description of the limit clause within a select statement
|
||||
*/
|
||||
struct LimitDescription {
|
||||
LimitDescription(int64_t limit, int64_t offset) :
|
||||
limit(limit),
|
||||
|
@ -49,7 +44,7 @@ struct LimitDescription {
|
|||
};
|
||||
|
||||
/**
|
||||
* @struct GroupByDescription
|
||||
* Description of the group-by clause within a select statement
|
||||
*/
|
||||
struct GroupByDescription {
|
||||
GroupByDescription() :
|
||||
|
@ -66,43 +61,40 @@ struct GroupByDescription {
|
|||
};
|
||||
|
||||
/**
|
||||
* @struct SelectStatement
|
||||
* @brief Representation of a full select statement.
|
||||
*
|
||||
* Representation of a full SQL select statement.
|
||||
* TODO: add union_order and union_limit
|
||||
*/
|
||||
struct SelectStatement : SQLStatement {
|
||||
SelectStatement() :
|
||||
SQLStatement(kStmtSelect),
|
||||
from_table(NULL),
|
||||
select_list(NULL),
|
||||
where_clause(NULL),
|
||||
group_by(NULL),
|
||||
union_select(NULL),
|
||||
fromTable(NULL),
|
||||
selectDistinct(false),
|
||||
selectList(NULL),
|
||||
whereClause(NULL),
|
||||
groupBy(NULL),
|
||||
unionSelect(NULL),
|
||||
order(NULL),
|
||||
limit(NULL) {};
|
||||
|
||||
virtual ~SelectStatement() {
|
||||
delete from_table;
|
||||
delete select_list;
|
||||
delete where_clause;
|
||||
delete group_by;
|
||||
delete fromTable;
|
||||
delete selectList;
|
||||
delete whereClause;
|
||||
delete groupBy;
|
||||
delete order;
|
||||
delete limit;
|
||||
}
|
||||
|
||||
TableRef* from_table;
|
||||
bool select_distinct;
|
||||
std::vector<Expr*>* select_list;
|
||||
Expr* where_clause;
|
||||
GroupByDescription* group_by;
|
||||
TableRef* fromTable;
|
||||
bool selectDistinct;
|
||||
std::vector<Expr*>* selectList;
|
||||
Expr* whereClause;
|
||||
GroupByDescription* groupBy;
|
||||
|
||||
SelectStatement* union_select;
|
||||
SelectStatement* unionSelect;
|
||||
OrderDescription* order;
|
||||
LimitDescription* limit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
|
@ -54,7 +54,9 @@ struct TableRef {
|
|||
/**
|
||||
* Convenience accessor methods
|
||||
*/
|
||||
inline bool hasSchema() { return schema != NULL; }
|
||||
inline bool hasSchema() {
|
||||
return schema != NULL;
|
||||
}
|
||||
|
||||
inline char* getName() {
|
||||
if (alias != NULL) return alias;
|
||||
|
|
|
@ -4,21 +4,16 @@
|
|||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
/**
|
||||
* @struct UpdateClause
|
||||
* @brief Represents "column = value" expressions
|
||||
* Represents "column = value" expressions
|
||||
*/
|
||||
struct UpdateClause {
|
||||
char* column;
|
||||
Expr* value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @struct UpdateStatement
|
||||
* @brief Represents "UPDATE"
|
||||
* Represents SQL Update statements.
|
||||
*/
|
||||
struct UpdateStatement : SQLStatement {
|
||||
UpdateStatement() :
|
||||
|
@ -39,7 +34,5 @@ struct UpdateStatement : SQLStatement {
|
|||
Expr* where;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namsepace hsql
|
||||
#endif
|
|
@ -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__
|
|
@ -5,138 +5,183 @@
|
|||
|
||||
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'); }
|
||||
void inprint(int64_t val, uint num_indent) { printf("%s%lld \n", indent(num_indent).c_str(), val); }
|
||||
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(const char* val, const char* val2, uint num_indent) { printf("%s%s->%s\n", indent(num_indent).c_str(), val, val2); }
|
||||
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); }
|
||||
std::string indent(uint numIndent) {
|
||||
return std::string(numIndent, '\t');
|
||||
}
|
||||
void inprint(int64_t val, uint numIndent) {
|
||||
printf("%s%ld \n", indent(numIndent).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) {
|
||||
case kTableName:
|
||||
inprint(table->name, num_indent);
|
||||
inprint(table->name, numIndent);
|
||||
break;
|
||||
case kTableSelect:
|
||||
printSelectStatementInfo(table->select, num_indent);
|
||||
printSelectStatementInfo(table->select, numIndent);
|
||||
break;
|
||||
case kTableJoin:
|
||||
inprint("Join Table", num_indent);
|
||||
inprint("Left", num_indent+1);
|
||||
printTableRefInfo(table->join->left, num_indent+2);
|
||||
inprint("Right", num_indent+1);
|
||||
printTableRefInfo(table->join->right, num_indent+2);
|
||||
inprint("Join Condition", num_indent+1);
|
||||
printExpression(table->join->condition, num_indent+2);
|
||||
inprint("Join Table", numIndent);
|
||||
inprint("Left", numIndent+1);
|
||||
printTableRefInfo(table->join->left, numIndent+2);
|
||||
inprint("Right", numIndent+1);
|
||||
printTableRefInfo(table->join->right, numIndent+2);
|
||||
inprint("Join Condition", numIndent+1);
|
||||
printExpression(table->join->condition, numIndent+2);
|
||||
break;
|
||||
case kTableCrossProduct:
|
||||
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent);
|
||||
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, numIndent);
|
||||
break;
|
||||
}
|
||||
if (table->alias != NULL) {
|
||||
inprint("Alias", num_indent+1);
|
||||
inprint(table->alias, num_indent+2);
|
||||
inprint("Alias", numIndent+1);
|
||||
inprint(table->alias, numIndent+2);
|
||||
}
|
||||
}
|
||||
|
||||
void printOperatorExpression(Expr* expr, uint num_indent) {
|
||||
if (expr == NULL) { inprint("null", num_indent); return; }
|
||||
void printOperatorExpression(Expr* expr, uint numIndent) {
|
||||
if (expr == NULL) {
|
||||
inprint("null", numIndent);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (expr->op_type) {
|
||||
case Expr::SIMPLE_OP: inprintC(expr->op_char, num_indent); break;
|
||||
case Expr::AND: inprint("AND", num_indent); break;
|
||||
case Expr::OR: inprint("OR", num_indent); break;
|
||||
case Expr::NOT: inprint("NOT", num_indent); break;
|
||||
default: inprintU(expr->op_type, num_indent); break;
|
||||
case Expr::SIMPLE_OP:
|
||||
inprintC(expr->op_char, numIndent);
|
||||
break;
|
||||
case Expr::AND:
|
||||
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);
|
||||
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1);
|
||||
printExpression(expr->expr, numIndent+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) {
|
||||
case kExprStar: inprint("*", num_indent); break;
|
||||
case kExprColumnRef: inprint(expr->name, num_indent); break;
|
||||
// case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break;
|
||||
case kExprLiteralFloat: inprint(expr->fval, num_indent); break;
|
||||
case kExprLiteralInt: inprint(expr->ival, num_indent); break;
|
||||
case kExprLiteralString: inprint(expr->name, num_indent); break;
|
||||
case kExprFunctionRef: inprint(expr->name, num_indent); inprint(expr->expr->name, num_indent+1); break;
|
||||
case kExprOperator: printOperatorExpression(expr, num_indent); break;
|
||||
default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return;
|
||||
case kExprStar:
|
||||
inprint("*", numIndent);
|
||||
break;
|
||||
case kExprColumnRef:
|
||||
inprint(expr->name, numIndent);
|
||||
break;
|
||||
// case kExprTableColumnRef: inprint(expr->table, expr->name, numIndent); break;
|
||||
case kExprLiteralFloat:
|
||||
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) {
|
||||
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) {
|
||||
inprint("SelectStatement", num_indent);
|
||||
inprint("Fields:", num_indent+1);
|
||||
for (Expr* expr : *stmt->select_list) printExpression(expr, num_indent+2);
|
||||
void printSelectStatementInfo(SelectStatement* stmt, uint numIndent) {
|
||||
inprint("SelectStatement", numIndent);
|
||||
inprint("Fields:", numIndent+1);
|
||||
for (Expr* expr : *stmt->selectList) printExpression(expr, numIndent+2);
|
||||
|
||||
inprint("Sources:", num_indent+1);
|
||||
printTableRefInfo(stmt->from_table, num_indent+2);
|
||||
inprint("Sources:", numIndent+1);
|
||||
printTableRefInfo(stmt->fromTable, numIndent+2);
|
||||
|
||||
if (stmt->where_clause != NULL) {
|
||||
inprint("Search Conditions:", num_indent+1);
|
||||
printExpression(stmt->where_clause, num_indent+2);
|
||||
if (stmt->whereClause != NULL) {
|
||||
inprint("Search Conditions:", numIndent+1);
|
||||
printExpression(stmt->whereClause, numIndent+2);
|
||||
}
|
||||
|
||||
|
||||
if (stmt->union_select != NULL) {
|
||||
inprint("Union:", num_indent+1);
|
||||
printSelectStatementInfo(stmt->union_select, num_indent+2);
|
||||
if (stmt->unionSelect != NULL) {
|
||||
inprint("Union:", numIndent+1);
|
||||
printSelectStatementInfo(stmt->unionSelect, numIndent+2);
|
||||
}
|
||||
|
||||
if (stmt->order != NULL) {
|
||||
inprint("OrderBy:", num_indent+1);
|
||||
printExpression(stmt->order->expr, num_indent+2);
|
||||
if (stmt->order->type == kOrderAsc) inprint("ascending", num_indent+2);
|
||||
else inprint("descending", num_indent+2);
|
||||
inprint("OrderBy:", numIndent+1);
|
||||
printExpression(stmt->order->expr, numIndent+2);
|
||||
if (stmt->order->type == kOrderAsc) inprint("ascending", numIndent+2);
|
||||
else inprint("descending", numIndent+2);
|
||||
}
|
||||
|
||||
if (stmt->limit != NULL) {
|
||||
inprint("Limit:", num_indent+1);
|
||||
inprint(stmt->limit->limit, num_indent+2);
|
||||
inprint("Limit:", numIndent+1);
|
||||
inprint(stmt->limit->limit, numIndent+2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printImportStatementInfo(ImportStatement* stmt, uint num_indent) {
|
||||
inprint("ImportStatment", num_indent);
|
||||
inprint(stmt->file_path, num_indent+1);
|
||||
inprint(stmt->table_name, num_indent+1);
|
||||
void printImportStatementInfo(ImportStatement* stmt, uint numIndent) {
|
||||
inprint("ImportStatment", numIndent);
|
||||
inprint(stmt->filePath, numIndent+1);
|
||||
inprint(stmt->tableName, numIndent+1);
|
||||
}
|
||||
|
||||
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent) {
|
||||
inprint("CreateStatment", num_indent);
|
||||
inprint(stmt->table_name, num_indent+1);
|
||||
inprint(stmt->file_path, num_indent+1);
|
||||
void printCreateStatementInfo(CreateStatement* stmt, uint numIndent) {
|
||||
inprint("CreateStatment", numIndent);
|
||||
inprint(stmt->tableName, numIndent+1);
|
||||
inprint(stmt->filePath, numIndent+1);
|
||||
}
|
||||
|
||||
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent) {
|
||||
inprint("InsertStatment", num_indent);
|
||||
inprint(stmt->table_name, num_indent+1);
|
||||
void printInsertStatementInfo(InsertStatement* stmt, uint numIndent) {
|
||||
inprint("InsertStatment", numIndent);
|
||||
inprint(stmt->tableName, numIndent+1);
|
||||
if (stmt->columns != NULL) {
|
||||
inprint("Columns", num_indent+1);
|
||||
inprint("Columns", numIndent+1);
|
||||
for (char* col_name : *stmt->columns) {
|
||||
inprint(col_name, num_indent+2);
|
||||
inprint(col_name, numIndent+2);
|
||||
}
|
||||
}
|
||||
switch (stmt->type) {
|
||||
case InsertStatement::kInsertValues:
|
||||
inprint("Values", num_indent+1);
|
||||
inprint("Values", numIndent+1);
|
||||
for (Expr* expr : *stmt->values) {
|
||||
printExpression(expr, num_indent+2);
|
||||
printExpression(expr, numIndent+2);
|
||||
}
|
||||
break;
|
||||
case InsertStatement::kInsertSelect:
|
||||
printSelectStatementInfo(stmt->select, num_indent+1);
|
||||
printSelectStatementInfo(stmt->select, numIndent+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
|
||||
#ifndef __SQLHELPER_H__
|
||||
#define __SQLHELPER_H__
|
||||
|
||||
|
||||
#include "sqltypes.h"
|
||||
#include "sql/statements.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
|
|
@ -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
|
|
@ -2,21 +2,21 @@
|
|||
#define __HELPER_H__
|
||||
|
||||
|
||||
#define TEST_PARSE_SQL_QUERY(query, output_var, num_statements) \
|
||||
SQLStatementList* output_var = SQLParser::parseSQLString(query); \
|
||||
ASSERT(output_var->isValid); \
|
||||
ASSERT_EQ(output_var->numStatements(), num_statements);
|
||||
#define TEST_PARSE_SQL_QUERY(query, outputVar, numStatements) \
|
||||
SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
|
||||
ASSERT(outputVar->isValid); \
|
||||
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); \
|
||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmt_type); \
|
||||
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(0);
|
||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmtType); \
|
||||
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(0);
|
||||
|
||||
|
||||
#define TEST_CAST_STMT(stmt_list, stmt_index, stmt_type, stmt_class, output_var) \
|
||||
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmt_type); \
|
||||
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(stmt_index);
|
||||
#define TEST_CAST_STMT(stmt_list, stmt_index, stmtType, stmtClass, outputVar) \
|
||||
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmtType); \
|
||||
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(stmt_index);
|
||||
|
||||
|
||||
#endif
|
|
@ -9,16 +9,16 @@ using namespace hsql;
|
|||
TEST(SelectTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt);
|
||||
|
||||
ASSERT_NULL(stmt->where_clause);
|
||||
ASSERT_NULL(stmt->group_by);
|
||||
ASSERT_NULL(stmt->whereClause);
|
||||
ASSERT_NULL(stmt->groupBy);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
ASSERT_FALSE(stmt->select_distinct);
|
||||
ASSERT_FALSE(stmt->selectDistinct);
|
||||
|
||||
GroupByDescription* group = stmt->group_by;
|
||||
GroupByDescription* group = stmt->groupBy;
|
||||
ASSERT_NOTNULL(group);
|
||||
ASSERT_EQ(group->columns->size(), 1);
|
||||
ASSERT(group->having->isSimpleOp('<'));
|
||||
|
@ -30,17 +30,17 @@ TEST(SelectHavingTest) {
|
|||
TEST(SelectDistinctTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt);
|
||||
|
||||
ASSERT(stmt->select_distinct);
|
||||
ASSERT_NULL(stmt->where_clause);
|
||||
ASSERT(stmt->selectDistinct);
|
||||
ASSERT_NULL(stmt->whereClause);
|
||||
}
|
||||
|
||||
TEST(SelectGroupDistinctTest) {
|
||||
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_EQ(stmt->select_list->size(), 3);
|
||||
ASSERT(!stmt->select_list->at(1)->distinct);
|
||||
ASSERT(stmt->select_list->at(2)->distinct);
|
||||
ASSERT_FALSE(stmt->selectDistinct);
|
||||
ASSERT_EQ(stmt->selectList->size(), 3);
|
||||
ASSERT(!stmt->selectList->at(1)->distinct);
|
||||
ASSERT(stmt->selectList->at(2)->distinct);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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-on-first-use.html
|
||||
public:
|
||||
static std::vector<std::string>& test_names() {
|
||||
static std::vector<std::string>* test_names = new std::vector<std::string>;
|
||||
return *test_names;
|
||||
static std::vector<std::string>& testNames() {
|
||||
static std::vector<std::string>* _testNames = new std::vector<std::string>;
|
||||
return *_testNames;
|
||||
}
|
||||
|
||||
static std::vector<void (*)(void)>& tests() {
|
||||
|
@ -22,34 +22,38 @@ public:
|
|||
|
||||
int AddTest(void (*foo)(void), std::string name) {
|
||||
TestsManager::tests().push_back(foo);
|
||||
TestsManager::test_names().push_back(name);
|
||||
TestsManager::testNames().push_back(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RunTests() {
|
||||
size_t num_failed = 0;
|
||||
size_t RunTests() {
|
||||
size_t numFailed = 0;
|
||||
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 {
|
||||
// Run test
|
||||
(*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) {
|
||||
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());
|
||||
num_failed++;
|
||||
numFailed++;
|
||||
}
|
||||
|
||||
}
|
||||
return numFailed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
RunTests();
|
||||
size_t numFailed = RunTests();
|
||||
if (numFailed == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -44,11 +44,6 @@ protected:
|
|||
std::string _msg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int AddTest(void (*foo)(void), std::string name);
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -33,17 +33,17 @@ int main(int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool expect_false = false;
|
||||
bool use_file = false;
|
||||
std::string file_path = "";
|
||||
bool expectFalse = false;
|
||||
bool useFile = false;
|
||||
std::string filePath = "";
|
||||
|
||||
// Parse command line arguments
|
||||
int i = 1;
|
||||
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")) {
|
||||
use_file = true;
|
||||
file_path = argv[++i];
|
||||
useFile = true;
|
||||
filePath = argv[++i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -52,44 +52,43 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// Read list of queries for this rest
|
||||
std::vector<std::string> queries;
|
||||
if (use_file) {
|
||||
queries = readlines(file_path);
|
||||
if (useFile) {
|
||||
queries = readlines(filePath);
|
||||
} else {
|
||||
for (; i < argc; ++i) queries.push_back(argv[i]);
|
||||
}
|
||||
|
||||
|
||||
// Execute queries
|
||||
int num_failed = 0;
|
||||
int numFailed = 0;
|
||||
for (std::string sql : queries) {
|
||||
// Measuring the parsing time
|
||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||
start = std::chrono::system_clock::now();
|
||||
|
||||
// Parsing
|
||||
SQLStatementList* stmt_list = SQLParser::parseSQLString(sql.c_str());
|
||||
SQLParserResult* stmt_list = SQLParser::parseSQLString(sql.c_str());
|
||||
|
||||
end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = end-start;
|
||||
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("\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());
|
||||
num_failed++;
|
||||
numFailed++;
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
|
||||
if (num_failed == 0) {
|
||||
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", num_failed, queries.size());
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -11,13 +11,13 @@ using namespace hsql;
|
|||
|
||||
|
||||
TEST(DeleteStatementTest) {
|
||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
||||
ASSERT(stmt_list->getStatement(0)->type() == kStmtDelete);
|
||||
SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||
ASSERT(result->isValid);
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
ASSERT(result->getStatement(0)->type() == kStmtDelete);
|
||||
|
||||
DeleteStatement* stmt = (DeleteStatement*) stmt_list->getStatement(0);
|
||||
ASSERT_STREQ(stmt->table_name, "students");
|
||||
DeleteStatement* stmt = (DeleteStatement*) result->getStatement(0);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->expr);
|
||||
ASSERT(stmt->expr->isType(kExprOperator));
|
||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||
|
@ -25,14 +25,14 @@ TEST(DeleteStatementTest) {
|
|||
}
|
||||
|
||||
TEST(CreateStatementTest) {
|
||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtCreate);
|
||||
SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||
ASSERT(result->isValid);
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
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_STREQ(stmt->table_name, "students");
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->columns);
|
||||
ASSERT_EQ(stmt->columns->size(), 4);
|
||||
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
||||
|
@ -47,12 +47,12 @@ TEST(CreateStatementTest) {
|
|||
|
||||
|
||||
TEST(UpdateStatementTest) {
|
||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtUpdate);
|
||||
SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||
ASSERT(result->isValid);
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
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_STREQ(stmt->table->name, "students");
|
||||
|
||||
|
@ -99,33 +99,33 @@ TEST(PrepareStatementTest) {
|
|||
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
||||
"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(stmt_list, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||
TEST_CAST_STMT(stmt_list, 2, kStmtDrop, DropStatement, drop);
|
||||
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
|
||||
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
||||
|
||||
// Prepare Statement #1
|
||||
ASSERT_STREQ(prep1->name, "test");
|
||||
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, 1, kStmtSelect, SelectStatement, select);
|
||||
|
||||
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->select_list->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->where_clause->expr2->isType(kExprPlaceholder));
|
||||
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
||||
|
||||
// Check IDs of placeholders
|
||||
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
||||
|
||||
ASSERT_EQ(select->select_list->at(0)->ival, 1);
|
||||
ASSERT_EQ(select->select_list->at(0), prep1->placeholders[1]);
|
||||
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
||||
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
||||
|
||||
ASSERT_EQ(select->where_clause->expr2->ival, 2);
|
||||
ASSERT_EQ(select->where_clause->expr2, prep1->placeholders[2]);
|
||||
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
||||
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
||||
|
||||
// Prepare Statement #2
|
||||
ASSERT_STREQ(prep2->name, "stmt");
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue