diff --git a/Makefile b/Makefile index 8504f8c..4bf9c0e 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ SRC = src SRCPARSER = src/parser # files -PARSERFILES = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp -LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp +PARSERCPP = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp +LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(PARSERCPP) LIBOBJ = $(LIBCPP:%.cpp=%.o) TESTCPP = $(shell find test/ -name '*.cpp') @@ -27,13 +27,16 @@ library: $(TARGET) $(TARGET): $(LIBOBJ) $(CXX) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ) -%.o: %.cpp $(PARSERFILES) +$(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp + $(CXX) $(CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration -Wno-deprecated-register + +%.o: %.cpp $(PARSERCPP) $(CXX) $(CFLAGS) -c -o $@ $< -$(SRCPARSER)/bison_parser.cpp: +$(SRCPARSER)/bison_parser.cpp: $(SRCPARSER)/bison_parser.y make -C $(SRCPARSER)/ bison_parser.cpp -$(SRCPARSER)/flex_lexer.cpp: +$(SRCPARSER)/flex_lexer.cpp: $(SRCPARSER)/flex_lexer.l make -C $(SRCPARSER)/ flex_lexer.cpp parser: @@ -51,6 +54,7 @@ cleanall: clean cleanparser install: cp $(TARGET) $(INSTALL)/lib/$(TARGET) + rm -rf $(INSTALL)/include/hsql cp -r src $(INSTALL)/include/hsql find $(INSTALL)/include/hsql -not -name '*.h' -type f | xargs rm diff --git a/README.md b/README.md index 8056e5e..26e9bca 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -C++ SQL Parser for Hyrise +C++ SQL Parser ========================= [![GitHub release](https://img.shields.io/github/release/hyrise/sql-parser.svg?maxAge=2592000)]() [![Build Status](https://img.shields.io/travis/hyrise/sql-parser.svg?maxAge=2592000)](https://travis-ci.org/hyrise/sql-parser) This is a SQL Parser for C++. It parses the given SQL query into C++ objects. -It is developed for integration in hyrise (https://github.com/hyrise/hyrise), but can be used in other environments as well. +It has been developed for integration in [Hyrise](https://github.com/hyrise/hyrise), but can be used perfectly well in other environments as well. In March 2015 we've also written a short paper outlining discussing some development details and the integration into our database Hyrise. You can find the paper [here](http://torpedro.com/paper/HyriseSQL-03-2015.pdf). -### Usage +## Usage **Note:** You can also find a detailed usage description at this [blog post](http://torpedro.github.io/tech/c++/sql/parser/2016/02/27/c++-sql-parser.html). @@ -21,52 +21,53 @@ To use the SQL parser in your own projects you simply have to follow these few s 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/master/example) - 5. Include the `SQLParser.h` from `src/` and link the library in your project + 3. *(Optional, Recommended)* Run `make install` to copy the library to `/usr/local/lib/` + 4. Run the tests `make test` to make sure everything worked + 5. Include the `SQLParser.h` from `src/` (or from `/usr/local/lib/hsql/` if you installed it) and link the library in your project + 6. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/master/example) +```cpp +#include "hsql/SQLParser.h" -### Extending the parser +/* ... */ -**Requirements for development:** - * gcc 4.8+ (or clang 3.4+) - * [bison](https://www.gnu.org/software/bison/) (v3.0.2+) - * [flex](http://flex.sourceforge.net/) (v2.5.5+) - -First step to extending this parser is cloning the repository `git clone git@github.com:hyrise/sql-parser.git` and making sure everything works by running the following steps: - -```bash -make parser # builds the bison parser and flex lexer -make library # builds the libsqlparser.so -make test # runs the tests with the library +{ + // Basic Usage Example + + const std::string query = "..."; + hsql::SQLParserResult result; + hsql::SQLParser::parseSQLString(query, &result); + + if (result.isValid() && result.size() > 0) { + const hsql::SQLStatement* statement = result.getStatement(0); + + if (statement.isType(hsql::SelectStatement)) { + const hsql::SelectStatement* select = (const hsql::SelectStatement*) statement; + /* ... */ + } + } +} ``` -Rerun these steps whenever you change part of the parse. To execute the entire pipeline automatically you can run: +Quick Links: -```bash -make cleanall # cleans the parser build and library build -make test # build parser, library and runs the tests -``` + * [SQLParser.h](src/SQLParser.h) + * [SQLParserResult.h](src/SQLParserResult.h) + * [SelectStatement.h](src/sql/SelectStatement.h) +## How to Contribute -#### How to contribute +**[Developer Documentation](docs/)** 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. -### Resources - - * [Working Syntax Examples](docs/syntax.md) - * [Developer Documentation](docs/dev-docs.md) - - -### License +## License HYRISE sql-parser is licensed as open source after the OpenSource "Licence of the Hasso-Plattner Institute" declared in the LICENSE file of this project. -### Contributers +## Contributers The following people contributed to HYRISE sql-parser in various forms. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..f519412 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,15 @@ +Documentation +============= + +Internal Links: + + * [Developer Documentation](dev-docs.md) + * [Working SQL Syntax Examples](syntax-examples.md) + + +External Resources: + + * [Original Dev-Paper (2015)](http://torpedro.com/paper/HyriseSQL-03-2015.pdf) + * [Blog Post about Basic Usage](http://torpedro.github.io/tech/c++/sql/parser/2016/02/27/c++-sql-parser.html) + + diff --git a/docs/dev-docs.md b/docs/dev-docs.md index 1214879..1d7aa6c 100644 --- a/docs/dev-docs.md +++ b/docs/dev-docs.md @@ -1,6 +1,29 @@ Developer Documentation ======================= +## Basic Requirements + +**Requirements for development:** + * gcc 4.8+ (or clang 3.4+) + * [bison](https://www.gnu.org/software/bison/) (v3.0.2+) + * [flex](http://flex.sourceforge.net/) (v2.5.5+) + +First step to extending this parser is cloning the repository `git clone git@github.com:hyrise/sql-parser.git` and making sure everything works by running the following steps: + +```bash +make parser # builds the bison parser and flex lexer +make library # builds the libsqlparser.so +make test # runs the tests with the library +``` + +Rerun these steps whenever you change part of the parse. To execute the entire pipeline automatically you can run: + +```bash +make cleanall # cleans the parser build and library build +make test # build parser, library and runs the tests +``` + + ## Developing New Functionality This section contains information about how to extend this parser with new functionalities. @@ -18,7 +41,7 @@ Finally you will need to include your new file in `src/sql/statements.h`. ### Extending the Grammar Related files: -```` +``` src/parser/bison_parser.y src/parser/flex_lexer.l src/parser/keywordlist_generator.py diff --git a/docs/syntax.md b/docs/syntax-examples.md similarity index 100% rename from docs/syntax.md rename to docs/syntax-examples.md diff --git a/src/SQLParserResult.cpp b/src/SQLParserResult.cpp index b8df999..6272b30 100644 --- a/src/SQLParserResult.cpp +++ b/src/SQLParserResult.cpp @@ -13,6 +13,16 @@ namespace hsql { addStatement(stmt); }; + // Move constructor. + SQLParserResult::SQLParserResult(SQLParserResult&& moved) { + isValid_ = moved.isValid_; + errorMsg_ = moved.errorMsg_; + statements_ = std::move(moved.statements_); + + moved.errorMsg_ = NULL; + moved.reset(); + } + SQLParserResult::~SQLParserResult() { reset(); } diff --git a/src/SQLParserResult.h b/src/SQLParserResult.h index 570664c..9ab82a4 100644 --- a/src/SQLParserResult.h +++ b/src/SQLParserResult.h @@ -15,6 +15,9 @@ namespace hsql { // Takes ownership of the statement. SQLParserResult(SQLStatement* stmt); + // Move constructor. + SQLParserResult(SQLParserResult&& moved); + // Deletes all statements in the result. virtual ~SQLParserResult(); diff --git a/src/parser/.gitignore b/src/parser/.gitignore index 0f274e7..1c0c561 100644 --- a/src/parser/.gitignore +++ b/src/parser/.gitignore @@ -1 +1,2 @@ -*.output \ No newline at end of file +*.output +conflict_test.cpp \ No newline at end of file diff --git a/src/parser/Makefile b/src/parser/Makefile index 10983c6..d8482b9 100644 --- a/src/parser/Makefile +++ b/src/parser/Makefile @@ -3,7 +3,7 @@ all: bison_parser.cpp flex_lexer.cpp bison_parser.cpp: bison_parser.y @bison --version | head -n 1 - bison bison_parser.y -v + bison bison_parser.y --output=bison_parser.cpp --defines=bison_parser.h --verbose flex_lexer.cpp: flex_lexer.l @flex --version @@ -14,4 +14,4 @@ clean: # Tests if the parser builds correctly and doesn't contain conflicts. test: - ! bison bison_parser.y -v 2>&1 | grep "conflict" >&2 + ! bison bison_parser.y -v --output=conflict_test.cpp 2>&1 | grep "conflict" >&2 diff --git a/src/parser/bison_parser.cpp b/src/parser/bison_parser.cpp index 4c71941..c9d213c 100644 --- a/src/parser/bison_parser.cpp +++ b/src/parser/bison_parser.cpp @@ -2558,7 +2558,7 @@ yyreduce: case 20: #line 315 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.import_stmt) = new ImportStatement((ImportStatement::ImportType) (yyvsp[-4].uval)); + (yyval.import_stmt) = new ImportStatement((ImportType) (yyvsp[-4].uval)); (yyval.import_stmt)->filePath = (yyvsp[-2].sval); (yyval.import_stmt)->tableName = (yyvsp[0].sval); } @@ -2567,7 +2567,7 @@ yyreduce: case 21: #line 323 "bison_parser.y" /* yacc.c:1646 */ - { (yyval.uval) = ImportStatement::kImportCSV; } + { (yyval.uval) = kImportCSV; } #line 2572 "bison_parser.cpp" /* yacc.c:1646 */ break; @@ -2580,7 +2580,7 @@ yyreduce: case 23: #line 337 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.create_stmt) = new CreateStatement(CreateStatement::kTableFromTbl); + (yyval.create_stmt) = new CreateStatement(kCreateTableFromTbl); (yyval.create_stmt)->ifNotExists = (yyvsp[-5].bval); (yyval.create_stmt)->tableName = (yyvsp[-4].sval); (yyval.create_stmt)->filePath = (yyvsp[0].sval); @@ -2591,7 +2591,7 @@ yyreduce: case 24: #line 343 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.create_stmt) = new CreateStatement(CreateStatement::kTable); + (yyval.create_stmt) = new CreateStatement(kCreateTable); (yyval.create_stmt)->ifNotExists = (yyvsp[-4].bval); (yyval.create_stmt)->tableName = (yyvsp[-3].sval); (yyval.create_stmt)->columns = (yyvsp[-1].column_vec); @@ -2602,7 +2602,7 @@ yyreduce: case 25: #line 349 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.create_stmt) = new CreateStatement(CreateStatement::kView); + (yyval.create_stmt) = new CreateStatement(kCreateView); (yyval.create_stmt)->ifNotExists = (yyvsp[-4].bval); (yyval.create_stmt)->tableName = (yyvsp[-3].sval); (yyval.create_stmt)->viewColumns = (yyvsp[-2].str_vec); @@ -2670,7 +2670,7 @@ yyreduce: case 35: #line 389 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.drop_stmt) = new DropStatement(DropStatement::kTable); + (yyval.drop_stmt) = new DropStatement(kDropTable); (yyval.drop_stmt)->name = (yyvsp[0].sval); } #line 2677 "bison_parser.cpp" /* yacc.c:1646 */ @@ -2679,7 +2679,7 @@ yyreduce: case 36: #line 393 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.drop_stmt) = new DropStatement(DropStatement::kView); + (yyval.drop_stmt) = new DropStatement(kDropView); (yyval.drop_stmt)->name = (yyvsp[0].sval); } #line 2686 "bison_parser.cpp" /* yacc.c:1646 */ @@ -2688,7 +2688,7 @@ yyreduce: case 37: #line 397 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.drop_stmt) = new DropStatement(DropStatement::kPreparedStatement); + (yyval.drop_stmt) = new DropStatement(kDropPreparedStatement); (yyval.drop_stmt)->name = (yyvsp[0].sval); } #line 2695 "bison_parser.cpp" /* yacc.c:1646 */ @@ -2716,7 +2716,7 @@ yyreduce: case 40: #line 429 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.insert_stmt) = new InsertStatement(InsertStatement::kInsertValues); + (yyval.insert_stmt) = new InsertStatement(kInsertValues); (yyval.insert_stmt)->tableName = (yyvsp[-5].sval); (yyval.insert_stmt)->columns = (yyvsp[-4].str_vec); (yyval.insert_stmt)->values = (yyvsp[-1].expr_vec); @@ -2727,7 +2727,7 @@ yyreduce: case 41: #line 435 "bison_parser.y" /* yacc.c:1646 */ { - (yyval.insert_stmt) = new InsertStatement(InsertStatement::kInsertSelect); + (yyval.insert_stmt) = new InsertStatement(kInsertSelect); (yyval.insert_stmt)->tableName = (yyvsp[-2].sval); (yyval.insert_stmt)->columns = (yyvsp[-1].str_vec); (yyval.insert_stmt)->select = (yyvsp[0].select_stmt); diff --git a/src/parser/bison_parser.y b/src/parser/bison_parser.y index c0252d0..faae931 100644 --- a/src/parser/bison_parser.y +++ b/src/parser/bison_parser.y @@ -56,9 +56,9 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha } } -// Define the names of the created files -%output "bison_parser.cpp" -%defines "bison_parser.h" +// Define the names of the created files (defined in Makefile) +// %output "bison_parser.cpp" +// %defines "bison_parser.h" // Tell bison to create a reentrant parser %define api.pure full @@ -313,14 +313,14 @@ execute_statement: ******************************/ import_statement: IMPORT FROM import_file_type FILE file_path INTO table_name { - $$ = new ImportStatement((ImportStatement::ImportType) $3); + $$ = new ImportStatement((ImportType) $3); $$->filePath = $5; $$->tableName = $7; } ; import_file_type: - CSV { $$ = ImportStatement::kImportCSV; } + CSV { $$ = kImportCSV; } ; file_path: @@ -335,19 +335,19 @@ file_path: ******************************/ create_statement: CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path { - $$ = new CreateStatement(CreateStatement::kTableFromTbl); + $$ = new CreateStatement(kCreateTableFromTbl); $$->ifNotExists = $3; $$->tableName = $4; $$->filePath = $8; } | CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' { - $$ = new CreateStatement(CreateStatement::kTable); + $$ = new CreateStatement(kCreateTable); $$->ifNotExists = $3; $$->tableName = $4; $$->columns = $6; } | CREATE VIEW opt_not_exists table_name opt_column_list AS select_statement { - $$ = new CreateStatement(CreateStatement::kView); + $$ = new CreateStatement(kCreateView); $$->ifNotExists = $3; $$->tableName = $4; $$->viewColumns = $5; @@ -387,15 +387,15 @@ column_type: drop_statement: DROP TABLE table_name { - $$ = new DropStatement(DropStatement::kTable); + $$ = new DropStatement(kDropTable); $$->name = $3; } | DROP VIEW table_name { - $$ = new DropStatement(DropStatement::kView); + $$ = new DropStatement(kDropView); $$->name = $3; } | DEALLOCATE PREPARE IDENTIFIER { - $$ = new DropStatement(DropStatement::kPreparedStatement); + $$ = new DropStatement(kDropPreparedStatement); $$->name = $3; } ; @@ -427,13 +427,13 @@ truncate_statement: ******************************/ insert_statement: INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' { - $$ = new InsertStatement(InsertStatement::kInsertValues); + $$ = new InsertStatement(kInsertValues); $$->tableName = $3; $$->columns = $4; $$->values = $7; } | INSERT INTO table_name opt_column_list select_no_paren { - $$ = new InsertStatement(InsertStatement::kInsertSelect); + $$ = new InsertStatement(kInsertSelect); $$->tableName = $3; $$->columns = $4; $$->select = $5; diff --git a/src/sql/CreateStatement.h b/src/sql/CreateStatement.h index 92e4d39..6751f30 100644 --- a/src/sql/CreateStatement.h +++ b/src/sql/CreateStatement.h @@ -23,16 +23,15 @@ namespace hsql { DataType type; }; + enum CreateType { + kCreateTable, + kCreateTableFromTbl, // Hyrise file format + kCreateView + }; // 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 - kView - }; - CreateStatement(CreateType type); virtual ~CreateStatement(); @@ -46,4 +45,5 @@ namespace hsql { }; } // namespace hsql + #endif diff --git a/src/sql/DeleteStatement.h b/src/sql/DeleteStatement.h index af34352..4c7d8ab 100644 --- a/src/sql/DeleteStatement.h +++ b/src/sql/DeleteStatement.h @@ -5,6 +5,7 @@ // Note: Implementations of constructors and destructors can be found in statements.cpp. namespace hsql { + // Represents SQL Delete statements. // Example: "DELETE FROM students WHERE grade > 3.0" // Note: if (expr == NULL) => delete all rows (truncate) @@ -17,4 +18,5 @@ namespace hsql { }; } // namespace hsql + #endif diff --git a/src/sql/DropStatement.h b/src/sql/DropStatement.h index 18b1363..5944463 100644 --- a/src/sql/DropStatement.h +++ b/src/sql/DropStatement.h @@ -5,21 +5,23 @@ // Note: Implementations of constructors and destructors can be found in statements.cpp. namespace hsql { + + enum DropType { + kDropTable, + kDropSchema, + kDropIndex, + kDropView, + kDropPreparedStatement + }; + // Represents SQL Delete statements. // Example "DROP TABLE students;" struct DropStatement : SQLStatement { - enum EntityType { - kTable, - kSchema, - kIndex, - kView, - kPreparedStatement - }; - DropStatement(EntityType type); + DropStatement(DropType type); virtual ~DropStatement(); - EntityType type; + DropType type; char* name; }; diff --git a/src/sql/ExecuteStatement.h b/src/sql/ExecuteStatement.h index 0bd9c42..99b87e7 100644 --- a/src/sql/ExecuteStatement.h +++ b/src/sql/ExecuteStatement.h @@ -4,10 +4,9 @@ #include "SQLStatement.h" namespace hsql { - /** - * Represents SQL Execute statements. - * Example: "EXECUTE ins_prep(100, "test", 2.3);" - */ + + // Represents SQL Execute statements. + // Example: "EXECUTE ins_prep(100, "test", 2.3);" struct ExecuteStatement : SQLStatement { ExecuteStatement(); virtual ~ExecuteStatement(); @@ -17,4 +16,5 @@ namespace hsql { }; } // namsepace hsql -#endif \ No newline at end of file + +#endif diff --git a/src/sql/Expr.h b/src/sql/Expr.h index bba37bd..5b9d4c8 100644 --- a/src/sql/Expr.h +++ b/src/sql/Expr.h @@ -6,7 +6,7 @@ #include namespace hsql { - class SelectStatement; + struct SelectStatement; // Helper function used by the lexer. // TODO: move to more appropriate place. diff --git a/src/sql/ImportStatement.h b/src/sql/ImportStatement.h index 1290713..1a63518 100644 --- a/src/sql/ImportStatement.h +++ b/src/sql/ImportStatement.h @@ -4,15 +4,13 @@ #include "SQLStatement.h" namespace hsql { - /** - * Represents SQL Import statements. - */ - struct ImportStatement : SQLStatement { - enum ImportType { - kImportCSV, - kImportTbl, // Hyrise file format - }; + enum ImportType { + kImportCSV, + kImportTbl, // Hyrise file format + }; + // Represents SQL Import statements. + struct ImportStatement : SQLStatement { ImportStatement(ImportType type); virtual ~ImportStatement(); @@ -23,5 +21,4 @@ namespace hsql { } // namespace hsql - -#endif \ No newline at end of file +#endif diff --git a/src/sql/InsertStatement.h b/src/sql/InsertStatement.h index 3aa8fd2..bea006e 100644 --- a/src/sql/InsertStatement.h +++ b/src/sql/InsertStatement.h @@ -5,16 +5,14 @@ #include "SelectStatement.h" namespace hsql { - /** - * Represents SQL Insert statements. - * Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)" - */ - struct InsertStatement : SQLStatement { - enum InsertType { - kInsertValues, - kInsertSelect - }; + enum InsertType { + kInsertValues, + kInsertSelect + }; + // Represents SQL Insert statements. + // Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)" + struct InsertStatement : SQLStatement { InsertStatement(InsertType type); virtual ~InsertStatement(); @@ -26,4 +24,5 @@ namespace hsql { }; } // namsepace hsql -#endif \ No newline at end of file + +#endif diff --git a/src/sql/PrepareStatement.h b/src/sql/PrepareStatement.h index 62891eb..55d38f7 100644 --- a/src/sql/PrepareStatement.h +++ b/src/sql/PrepareStatement.h @@ -7,20 +7,15 @@ #include namespace hsql { - /** - * Represents SQL Prepare statements. - * Example: "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(); virtual ~PrepareStatement(); - /** - * 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 - */ + // 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. void setPlaceholders(std::vector ph); char* name; @@ -35,4 +30,5 @@ namespace hsql { }; } // namsepace hsql -#endif \ No newline at end of file + +#endif diff --git a/src/sql/SQLStatement.h b/src/sql/SQLStatement.h index 9d491d4..ccfddf1 100644 --- a/src/sql/SQLStatement.h +++ b/src/sql/SQLStatement.h @@ -21,10 +21,9 @@ namespace hsql { kStmtAlter }; - /** - * Base struct for every SQL statement - */ + // Base struct for every SQL statement struct SQLStatement { + SQLStatement(StatementType type); virtual ~SQLStatement(); @@ -33,9 +32,14 @@ namespace hsql { bool isType(StatementType type) const; + // Shorthand for isType(type). + bool is(StatementType type) const; + private: StatementType type_; + }; } // namespace hsql + #endif // __SQLPARSER__SQLSTATEMENT_H__ diff --git a/src/sql/SelectStatement.h b/src/sql/SelectStatement.h index 095310e..d826db3 100644 --- a/src/sql/SelectStatement.h +++ b/src/sql/SelectStatement.h @@ -11,9 +11,8 @@ namespace hsql { kOrderDesc }; - /** - * Description of the order by clause within a select statement - */ + + // Description of the order by clause within a select statement. struct OrderDescription { OrderDescription(OrderType type, Expr* expr); virtual ~OrderDescription(); @@ -25,9 +24,7 @@ namespace hsql { const int64_t kNoLimit = -1; const int64_t kNoOffset = -1; - /** - * Description of the limit clause within a select statement - */ + // Description of the limit clause within a select statement. struct LimitDescription { LimitDescription(int64_t limit, int64_t offset); @@ -35,9 +32,7 @@ namespace hsql { int64_t offset; }; - /** - * Description of the group-by clause within a select statement - */ + // Description of the group-by clause within a select statement. struct GroupByDescription { GroupByDescription(); virtual ~GroupByDescription(); @@ -46,10 +41,8 @@ namespace hsql { Expr* having; }; - /** - * Representation of a full SQL select statement. - * TODO: add union_order and union_limit - */ + // Representation of a full SQL select statement. + // TODO: add union_order and union_limit. struct SelectStatement : SQLStatement { SelectStatement(); virtual ~SelectStatement(); @@ -66,4 +59,5 @@ namespace hsql { }; } // namespace hsql -#endif \ No newline at end of file + +#endif diff --git a/src/sql/UpdateStatement.h b/src/sql/UpdateStatement.h index 744d55b..eb07a6a 100644 --- a/src/sql/UpdateStatement.h +++ b/src/sql/UpdateStatement.h @@ -4,17 +4,14 @@ #include "SQLStatement.h" namespace hsql { - /** - * Represents "column = value" expressions - */ + + // Represents "column = value" expressions. struct UpdateClause { char* column; Expr* value; }; - /** - * Represents SQL Update statements. - */ + // Represents SQL Update statements. struct UpdateStatement : SQLStatement { UpdateStatement(); virtual ~UpdateStatement(); @@ -26,4 +23,5 @@ namespace hsql { }; } // namsepace hsql -#endif \ No newline at end of file + +#endif diff --git a/src/sql/statements.cpp b/src/sql/statements.cpp index bcdece3..5a818f6 100644 --- a/src/sql/statements.cpp +++ b/src/sql/statements.cpp @@ -17,6 +17,10 @@ namespace hsql { return (type_ == type); } + bool SQLStatement::is(StatementType type) const { + return isType(type); + } + // ColumnDefinition ColumnDefinition::ColumnDefinition(char* name, DataType type) : name(name), @@ -69,7 +73,7 @@ namespace hsql { } // DropStatament - DropStatement::DropStatement(EntityType type) : + DropStatement::DropStatement(DropType type) : SQLStatement(kStmtDrop), type(type), name(NULL) {} diff --git a/src/util/sqlhelper.cpp b/src/util/sqlhelper.cpp index 36aefc8..352990a 100644 --- a/src/util/sqlhelper.cpp +++ b/src/util/sqlhelper.cpp @@ -11,7 +11,7 @@ namespace hsql { return std::string(numIndent, '\t'); } void inprint(int64_t val, uintmax_t numIndent) { - printf("%s%lld \n", indent(numIndent).c_str(), val); + printf("%s%ld \n", indent(numIndent).c_str(), val); } void inprint(float val, uintmax_t numIndent) { printf("%s%f\n", indent(numIndent).c_str(), val); @@ -26,7 +26,7 @@ namespace hsql { printf("%s%c\n", indent(numIndent).c_str(), val); } void inprintU(uint64_t val, uintmax_t numIndent) { - printf("%s%llu\n", indent(numIndent).c_str(), val); + printf("%s%lu\n", indent(numIndent).c_str(), val); } void printTableRefInfo(TableRef* table, uintmax_t numIndent) { @@ -174,13 +174,13 @@ namespace hsql { } } switch (stmt->type) { - case InsertStatement::kInsertValues: + case kInsertValues: inprint("Values", numIndent + 1); for (Expr* expr : *stmt->values) { printExpression(expr, numIndent + 2); } break; - case InsertStatement::kInsertSelect: + case kInsertSelect: printSelectStatementInfo(stmt->select, numIndent + 1); break; } diff --git a/test/prepare_tests.cpp b/test/prepare_tests.cpp index bd8c51d..e8eeaea 100644 --- a/test/prepare_tests.cpp +++ b/test/prepare_tests.cpp @@ -11,6 +11,8 @@ using hsql::kStmtInsert; using hsql::kStmtPrepare; using hsql::kStmtSelect; +using hsql::kDropPreparedStatement; + using hsql::DropStatement; using hsql::ExecuteStatement; using hsql::InsertStatement; @@ -69,7 +71,7 @@ TEST(PrepareMultiStatementTest) { ASSERT_EQ(prep2->placeholders.size(), 1); // Deallocate Statement - ASSERT_EQ(drop->type, DropStatement::kPreparedStatement); + ASSERT_EQ(drop->type, kDropPreparedStatement); ASSERT_STREQ(drop->name, "stmt"); } diff --git a/test/sql_tests.cpp b/test/sql_tests.cpp index fce09d9..1546d71 100644 --- a/test/sql_tests.cpp +++ b/test/sql_tests.cpp @@ -37,7 +37,7 @@ TEST(CreateStatementTest) { ASSERT_EQ(result.getStatement(0)->type(), kStmtCreate); const CreateStatement* stmt = (const CreateStatement*) result.getStatement(0); - ASSERT_EQ(stmt->type, CreateStatement::kTable); + ASSERT_EQ(stmt->type, kCreateTable); ASSERT_STREQ(stmt->tableName, "students"); ASSERT_NOTNULL(stmt->columns); ASSERT_EQ(stmt->columns->size(), 4); @@ -102,7 +102,7 @@ TEST(DropTableStatementTest) { result, stmt); - ASSERT_EQ(stmt->type, DropStatement::kTable); + ASSERT_EQ(stmt->type, kDropTable); ASSERT_NOTNULL(stmt->name); ASSERT_STREQ(stmt->name, "students"); } @@ -127,4 +127,33 @@ TEST(ReleaseStatementTest) { } } + +SQLParserResult parse_and_move(std::string query) { + hsql::SQLParserResult result; + hsql::SQLParser::parseSQLString(query, &result); + // Moves on return. + return result; +} + +SQLParserResult move_in_and_back(SQLParserResult res) { + // Moves on return. + return res; +} + +TEST(MoveSQLResultTest) { + SQLParserResult res = parse_and_move("SELECT * FROM test;"); + ASSERT(res.isValid()); + ASSERT_EQ(1, res.size()); + + // Moved around. + SQLParserResult new_res = move_in_and_back(std::move(res)); + + // Original object should be invalid. + ASSERT_FALSE(res.isValid()); + ASSERT_EQ(0, res.size()); + + ASSERT(new_res.isValid()); + ASSERT_EQ(1, new_res.size()); +} + TEST_MAIN(); diff --git a/test/thirdparty/microtest/microtest.h b/test/thirdparty/microtest/microtest.h index f6cb4b7..b7c8392 100644 --- a/test/thirdparty/microtest/microtest.h +++ b/test/thirdparty/microtest/microtest.h @@ -1,9 +1,9 @@ // -// microtest +// microtest.h // -// URL: https://github.com/torpedro/microtest +// URL: https://github.com/torpedro/microtest.h // Author: Pedro Flemming (http://torpedro.com/) -// License: MIT License (https://github.com/torpedro/microtest/blob/master/LICENSE) +// License: MIT License (https://github.com/torpedro/microtest.h/blob/master/LICENSE) // Copyright (c) 2017 Pedro Flemming // // This is a small header-only C++ unit testing framework. @@ -37,8 +37,18 @@ ASSERT_TRUE(value != NULL); #define ASSERT_STREQ(a, b)\ - if (std::string(a).compare(std::string(b)) != 0)\ - throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__); + if (std::string(a).compare(std::string(b)) != 0) {\ + printf("%s{ info} %s", mt::yellow(), mt::def());\ + std::cout << "Actual values: " << a << " != " << b << std::endl;\ + throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__);\ + } + +#define ASSERT_STRNEQ(a, b)\ + if (std::string(a).compare(std::string(b)) !== 0) {\ + printf("%s{ info} %s", mt::yellow(), mt::def());\ + std::cout << "Actual values: " << a << " == " << b << std::endl;\ + throw mt::AssertFailedException(#a " != " #b, __FILE__, __LINE__);\ + } #define ASSERT_EQ(a, b)\ if (a != b) {\ @@ -175,7 +185,8 @@ namespace mt { } } - return num_failed; + int return_code = (num_failed > 0) ? 1 : 0; + return return_code; } }; @@ -210,4 +221,4 @@ namespace mt { }\ } -#endif // __MICROTEST_H__ +#endif // __MICROTEST_H__ \ No newline at end of file