From c5d3a84395952a4661122c7c60602b05717d9783 Mon Sep 17 00:00:00 2001 From: Pedro Date: Fri, 7 Nov 2014 02:00:09 +0100 Subject: [PATCH] query parser now returns a list of statements --- src/build_and_run_tests.sh | 4 +++- src/lib/Expr.cpp | 4 ++++ src/lib/Expr.h | 1 + src/lib/ImportStatement.h | 2 +- src/lib/List.h | 10 +++++++-- src/lib/Statement.h | 13 ++++++++++++ src/lib/sqlhelper.cpp | 12 +++++++++-- src/lib/sqlhelper.h | 1 + src/parser/SQLParser.cpp | 12 +++++------ src/parser/SQLParser.h | 2 +- src/parser/bison_parser.y | 42 +++++++++++++++++++++++++++----------- src/sql_analysis.cpp | 31 +++++++++++++++++----------- src/sql_grammar_test.cpp | 8 ++++---- 13 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/build_and_run_tests.sh b/src/build_and_run_tests.sh index ea396d7..dcd0826 100644 --- a/src/build_and_run_tests.sh +++ b/src/build_and_run_tests.sh @@ -32,6 +32,8 @@ echo "\n\n" # ./bin/analysis "-- test # SELECT * FROM table WHERE a NOT LIKE '%s' -- inline comment # --my comment" -# ./bin/analysis "SELECT * from table WHERE (b OR NOT a) AND a = 12.5 JOIN table2 ON a = b" +./bin/analysis " +IMPORT FROM TBL FILE 'students.tbl' INTO table; +SELECT * FROM table;" echo "\n\n" \ No newline at end of file diff --git a/src/lib/Expr.cpp b/src/lib/Expr.cpp index c1c590f..0e802e6 100644 --- a/src/lib/Expr.cpp +++ b/src/lib/Expr.cpp @@ -86,4 +86,8 @@ Expr* Expr::makeFunctionRef(char* func_name, Expr* expr) { return e; } +// Expr::~Expr() { + +// } + } // namespace hsql \ No newline at end of file diff --git a/src/lib/Expr.h b/src/lib/Expr.h index e992cfc..35ecd6a 100644 --- a/src/lib/Expr.h +++ b/src/lib/Expr.h @@ -45,6 +45,7 @@ struct Expr { Expr(ExprType type) : type(type) {}; + // virtual ~Expr(); ExprType type; diff --git a/src/lib/ImportStatement.h b/src/lib/ImportStatement.h index 5ecc7c1..2113434 100644 --- a/src/lib/ImportStatement.h +++ b/src/lib/ImportStatement.h @@ -19,7 +19,7 @@ typedef enum { * @struct ImportStatement */ struct ImportStatement : Statement { - ImportStatement() : Statement(kStmtSelect) {}; + ImportStatement() : Statement(kStmtImport) {}; ImportFileType file_type; const char* file_path; diff --git a/src/lib/List.h b/src/lib/List.h index c031678..3492ee2 100644 --- a/src/lib/List.h +++ b/src/lib/List.h @@ -11,8 +11,6 @@ namespace hsql { template class List { public: - std::vector<_T> _vector; - List() {} List(_T first_value) { @@ -23,7 +21,15 @@ public: inline _T at(int i) { return _vector[i]; } inline _T &operator[](int i) { return _vector[i]; } + inline void push_back(_T value) { _vector.push_back(value); } + + inline std::vector<_T> vector() { return _vector; }; + + +private: + std::vector<_T> _vector; + }; diff --git a/src/lib/Statement.h b/src/lib/Statement.h index c82ede2..0487847 100644 --- a/src/lib/Statement.h +++ b/src/lib/Statement.h @@ -5,9 +5,11 @@ #ifndef __STATEMENT_H__ #define __STATEMENT_H__ +#include "List.h" namespace hsql { + typedef enum { kStmtError, kStmtSelect, @@ -27,8 +29,19 @@ struct Statement { Statement(StatementType type) : type(type) {}; StatementType type; +}; + + +class StatementList : public List { +public: + StatementList() : List(), isValid(true) {}; + StatementList(Statement* stmt) : List(stmt), isValid(true) {}; + + bool isValid; const char* parser_msg; }; +// typedef List StatementList; + } // namespace hsql diff --git a/src/lib/sqlhelper.cpp b/src/lib/sqlhelper.cpp index 2ff0680..3c3ee8f 100644 --- a/src/lib/sqlhelper.cpp +++ b/src/lib/sqlhelper.cpp @@ -34,7 +34,7 @@ void printTableRefInfo(TableRef* table, uint num_indent) { printExpression(table->join_condition, num_indent+2); break; case kTableCrossProduct: - for (TableRef* tbl : table->list->_vector) printTableRefInfo(tbl, num_indent); + for (TableRef* tbl : table->list->vector()) printTableRefInfo(tbl, num_indent); break; } if (table->alias != NULL) { @@ -74,7 +74,7 @@ void printExpression(Expr* expr, uint num_indent) { void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) { inprint("SelectStatement", num_indent); inprint("Fields:", num_indent+1); - for (Expr* expr : stmt->select_list->_vector) printExpression(expr, num_indent+2); + for (Expr* expr : stmt->select_list->vector()) printExpression(expr, num_indent+2); inprint("Sources:", num_indent+1); printTableRefInfo(stmt->from_table, num_indent+2); @@ -98,4 +98,12 @@ void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) { } + +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); +} + + } // namespace hsql \ No newline at end of file diff --git a/src/lib/sqlhelper.h b/src/lib/sqlhelper.h index f1006bd..90bf944 100644 --- a/src/lib/sqlhelper.h +++ b/src/lib/sqlhelper.h @@ -8,6 +8,7 @@ namespace hsql { void printSelectStatementInfo(SelectStatement* stmt, uint num_indent); +void printImportStatementInfo(ImportStatement* stmt, uint num_indent); } // namespace hsql diff --git a/src/parser/SQLParser.cpp b/src/parser/SQLParser.cpp index 578193f..c5638d1 100644 --- a/src/parser/SQLParser.cpp +++ b/src/parser/SQLParser.cpp @@ -3,8 +3,6 @@ #include "flex_lexer.h" #include -// int yyparse(Statement **expression, yyscan_t scanner); - namespace hsql { @@ -13,8 +11,8 @@ SQLParser::SQLParser() { } -Statement* SQLParser::parseSQLString(const char *text) { - Statement* stmt; +StatementList* SQLParser::parseSQLString(const char *text) { + StatementList* result; yyscan_t scanner; YY_BUFFER_STATE state; @@ -26,15 +24,15 @@ Statement* SQLParser::parseSQLString(const char *text) { state = hsql__scan_string(text, scanner); - if (hsql_parse(&stmt, scanner)) { + if (hsql_parse(&result, scanner)) { // Returns an error stmt object - return stmt; + return result; } hsql__delete_buffer(state, scanner); hsql_lex_destroy(scanner); - return stmt; + return result; } } // namespace hsql \ No newline at end of file diff --git a/src/parser/SQLParser.h b/src/parser/SQLParser.h index 47d5f07..5719aa7 100644 --- a/src/parser/SQLParser.h +++ b/src/parser/SQLParser.h @@ -8,7 +8,7 @@ namespace hsql { class SQLParser { public: - static Statement* parseSQLString(const char* sql); + static StatementList* parseSQLString(const char* sql); private: SQLParser(); diff --git a/src/parser/bison_parser.y b/src/parser/bison_parser.y index b1b8c38..4a8c288 100644 --- a/src/parser/bison_parser.y +++ b/src/parser/bison_parser.y @@ -19,9 +19,13 @@ using namespace hsql; -int yyerror(Statement **stmt, yyscan_t scanner, const char *msg) { - *stmt = new Statement(kStmtError); - (*stmt)->parser_msg = strdup(msg); +int yyerror(StatementList** result, yyscan_t scanner, const char *msg) { + + StatementList* list = new StatementList(); + list->isValid = false; + list->parser_msg = strdup(msg); + *result = list; + return 0; } @@ -60,7 +64,7 @@ typedef void* yyscan_t; %lex-param { yyscan_t scanner } // Define additional parameters for yyparse -%parse-param { hsql::Statement **statement } +%parse-param { hsql::StatementList** result } %parse-param { yyscan_t scanner } @@ -83,9 +87,10 @@ typedef void* yyscan_t; hsql::OrderType order_type; hsql::LimitDescription* limit; + hsql::StatementList* stmt_list; hsql::List* slist; - hsql::List* explist; - hsql::List* tbllist; + hsql::List* expr_list; + hsql::List* table_list; } @@ -107,6 +112,7 @@ typedef void* yyscan_t; /********************************* ** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html) *********************************/ +%type statement_list %type statement %type select_statement %type import_statement @@ -114,10 +120,10 @@ typedef void* yyscan_t; %type from_clause table_ref table_ref_atomic table_ref_name %type
join_clause join_table %type expr scalar_expr unary_expr binary_expr function_expr star_expr -%type column_name literal int_literal num_literal +%type column_name literal int_literal num_literal string_literal %type comp_expr where_clause join_condition -%type expr_list group_clause select_list -%type table_ref_commalist +%type expr_list group_clause select_list +%type table_ref_commalist %type order_by_clause %type limit_clause %type order_type @@ -156,9 +162,16 @@ typedef void* yyscan_t; // Defines our general input. // TODO: Support list of statements input: - statement opt_semicolon { *statement = $1; } + statement_list opt_semicolon { *result = $1; } ; + +statement_list: + statement { $$ = new StatementList($1); } + | statement_list ';' statement { $1->push_back($3); $$ = $1; } + ; + + // All types of statements // TODO: insert, delete, etc... statement: @@ -186,7 +199,7 @@ import_file_type: ; file_path: - STRING + string_literal { $$ = $1->name; } ; @@ -308,10 +321,15 @@ column_name: ; literal: - STRING { $$ = Expr::makeLiteral($1); } + string_literal | num_literal ; +string_literal: + STRING { $$ = Expr::makeLiteral($1); } + ; + + num_literal: FLOAT { $$ = Expr::makeLiteral($1); } | int_literal diff --git a/src/sql_analysis.cpp b/src/sql_analysis.cpp index 980c7c5..dcf9ffa 100644 --- a/src/sql_analysis.cpp +++ b/src/sql_analysis.cpp @@ -15,23 +15,30 @@ int main(int argc, char *argv[]) { for (int n = 1; n < argc; ++n) { char* sql = argv[n]; - printf("\nEvaluating Statement \"%s\"\n", sql); - Statement* stmt = SQLParser::parseSQLString(sql); + printf("\nEvaluating Query \"%s\"\n", sql); + StatementList* stmt_list = SQLParser::parseSQLString(sql); - if (stmt == NULL) { - fprintf(stderr, "Parsing of \"%s\" failed!\n", sql); + if (!stmt_list->isValid) { + fprintf(stderr, "Parsing of \"%s\" failed! Reason: %s\n", sql, stmt_list->parser_msg); continue; } - if (stmt->type == kStmtSelect) { - printSelectStatementInfo((SelectStatement*) stmt, 0); - } else { - if (stmt->type == kStmtError) { - fprintf(stderr, "%s!\n", stmt->parser_msg); - } else { - fprintf(stderr, "Unsupported Statement Type %u!\n", stmt->type); + int i = 0; + for (Statement* stmt : stmt_list->vector()) { + printf("Statement %d:\n", i++); + switch (stmt->type) { + case kStmtSelect: + printSelectStatementInfo((SelectStatement*) stmt, 1); + break; + case kStmtImport: + printImportStatementInfo((ImportStatement*) stmt, 1); + break; + default: + fprintf(stderr, "\tStatement Type %u. No detailed print method available.\n", stmt->type); + break; + } - } + } } return 0; diff --git a/src/sql_grammar_test.cpp b/src/sql_grammar_test.cpp index d9b3e1d..27f3aa6 100644 --- a/src/sql_grammar_test.cpp +++ b/src/sql_grammar_test.cpp @@ -23,17 +23,17 @@ int main(int argc, char *argv[]) { start = std::chrono::system_clock::now(); // Parsing - Statement* stmt = SQLParser::parseSQLString(sql); + StatementList* stmt_list = SQLParser::parseSQLString(sql); end = std::chrono::system_clock::now(); std::chrono::duration elapsed_seconds = end-start; - if (expectFalse != (stmt->type == kStmtError)) { - fprintf(stderr, "-> Failed (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt->parser_msg, sql); + if (expectFalse == stmt_list->isValid) { + fprintf(stderr, "-> Failed (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt_list->parser_msg, sql); continue; } else { if (expectFalse) { - printf("Success (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt->parser_msg, sql); + printf("Success (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt_list->parser_msg, sql); } else { printf("Success (%.3fms)! \"%s\"\n", elapsed_seconds.count()*1000, sql);