diff --git a/src/parser/SQLParser.cpp b/src/parser/SQLParser.cpp index 6c11f0e..92f51ec 100644 --- a/src/parser/SQLParser.cpp +++ b/src/parser/SQLParser.cpp @@ -34,5 +34,10 @@ SQLStatementList* SQLParser::parseSQLString(const char *text) { hsql_lex_destroy(scanner); return result; } + +SQLStatementList* SQLParser::parseSQLString(const std::string& text) { + return parseSQLString(text.c_str()); +} + } // namespace hsql \ No newline at end of file diff --git a/src/parser/SQLParser.h b/src/parser/SQLParser.h index b41e5b8..ae8d330 100644 --- a/src/parser/SQLParser.h +++ b/src/parser/SQLParser.h @@ -16,6 +16,7 @@ namespace hsql { class SQLParser { public: static SQLStatementList* parseSQLString(const char* sql); + static SQLStatementList* parseSQLString(const std::string& sql); private: SQLParser(); diff --git a/src/parser/bison_parser.y b/src/parser/bison_parser.y index 3ed1f7b..ed1c345 100644 --- a/src/parser/bison_parser.y +++ b/src/parser/bison_parser.y @@ -224,11 +224,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c // Defines our general input. input: - prepare_statement { - $1->setPlaceholders(yyloc.placeholder_list); - *result = new SQLStatementList($1); - } - | statement_list opt_semicolon { + statement_list opt_semicolon { *result = $1; } ; @@ -240,7 +236,12 @@ statement_list: ; statement: - preparable_statement + prepare_statement { + $1->setPlaceholders(yyloc.placeholder_list); + yyloc.placeholder_list.clear(); + $$ = $1; + } + | preparable_statement ; @@ -261,7 +262,12 @@ preparable_statement: * Prepared Statement ******************************/ prepare_statement: - PREPARE IDENTIFIER ':' statement_list opt_semicolon { + PREPARE IDENTIFIER ':' preparable_statement { + $$ = new PrepareStatement(); + $$->name = $2; + $$->query = new SQLStatementList($4); + } + | PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' { $$ = new PrepareStatement(); $$->name = $2; $$->query = $4; diff --git a/src/parser/flex_lexer.l b/src/parser/flex_lexer.l index b3f657e..941104e 100644 --- a/src/parser/flex_lexer.l +++ b/src/parser/flex_lexer.l @@ -177,7 +177,7 @@ TO TOKEN(TO) ">=" TOKEN(GREATEREQ) -[-+*/(),.;<>=^%:?] { return yytext[0]; } +[-+*/(){},.;<>=^%:?] { return yytext[0]; } [0-9]+"."[0-9]* | diff --git a/src/sql_tests.cpp b/src/sql_tests.cpp index 7b4e32d..2162ba0 100644 --- a/src/sql_tests.cpp +++ b/src/sql_tests.cpp @@ -75,22 +75,16 @@ TEST(UpdateStatementTest) { TEST(InsertStatementTest) { - SQLStatementList* stmt_list = SQLParser::parseSQLString("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)"); - ASSERT(stmt_list->isValid); - ASSERT_EQ(stmt_list->numStatements(), 1); - ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtInsert); + TEST_PARSE_SINGLE_SQL("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)", kStmtInsert, InsertStatement, stmt); + ASSERT_EQ(stmt->values->size(), 4); // TODO } TEST(DropTableStatementTest) { - SQLStatementList* stmt_list = SQLParser::parseSQLString("DROP TABLE students"); - ASSERT(stmt_list->isValid); - ASSERT_EQ(stmt_list->numStatements(), 1); - ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtDrop); + TEST_PARSE_SINGLE_SQL("DROP TABLE students", kStmtDrop, DropStatement, stmt); - DropStatement* stmt = (DropStatement*) stmt_list->getStatement(0); ASSERT_EQ(stmt->type, DropStatement::kTable); ASSERT_NOTNULL(stmt->name); ASSERT_STREQ(stmt->name, "students"); @@ -98,22 +92,30 @@ TEST(DropTableStatementTest) { TEST(PrepareStatementTest) { - TEST_PARSE_SINGLE_SQL("PREPARE test:" + std::string query = "PREPARE test {" "INSERT INTO test VALUES(?);" "SELECT ?, test FROM test WHERE c1 = ?;" - "", kStmtPrepare, PrepareStatement, prep_stmt); + "};" + "PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"; - ASSERT_STREQ(prep_stmt->name, "test"); - ASSERT_EQ(prep_stmt->placeholders.size(), 3); + TEST_PARSE_SQL_QUERY(query, stmt_list, 2); + ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtPrepare); + ASSERT_EQ(stmt_list->getStatement(1)->type(), kStmtPrepare); - ASSERT_EQ(prep_stmt->query->numStatements(), 2); - ASSERT_EQ(prep_stmt->query->getStatement(0)->type(), kStmtInsert); - ASSERT_EQ(prep_stmt->query->getStatement(1)->type(), kStmtSelect); + PrepareStatement* prep1 = (PrepareStatement*) stmt_list->getStatement(0); + PrepareStatement* prep2 = (PrepareStatement*) stmt_list->getStatement(1); + // Prepare Statement #1 + ASSERT_STREQ(prep1->name, "test"); + ASSERT_EQ(prep1->placeholders.size(), 3); - InsertStatement* insert = (InsertStatement*) prep_stmt->query->getStatement(0); - SelectStatement* select = (SelectStatement*) prep_stmt->query->getStatement(1); + ASSERT_EQ(prep1->query->numStatements(), 2); + ASSERT_EQ(prep1->query->getStatement(0)->type(), kStmtInsert); + ASSERT_EQ(prep1->query->getStatement(1)->type(), kStmtSelect); + + InsertStatement* insert = (InsertStatement*) prep1->query->getStatement(0); + SelectStatement* select = (SelectStatement*) prep1->query->getStatement(1); ASSERT(insert->values->at(0)->isType(kExprPlaceholder)); ASSERT(select->select_list->at(0)->isType(kExprPlaceholder)); @@ -121,13 +123,17 @@ TEST(PrepareStatementTest) { // Check IDs of placeholders ASSERT_EQ(insert->values->at(0)->ival, 0); - ASSERT_EQ(insert->values->at(0), prep_stmt->placeholders[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), prep_stmt->placeholders[1]); + ASSERT_EQ(select->select_list->at(0), prep1->placeholders[1]); ASSERT_EQ(select->where_clause->expr2->ival, 2); - ASSERT_EQ(select->where_clause->expr2, prep_stmt->placeholders[2]); + ASSERT_EQ(select->where_clause->expr2, prep1->placeholders[2]); + + // Prepare Statement #2 + ASSERT_STREQ(prep2->name, "stmt"); + ASSERT_EQ(prep2->placeholders.size(), 1); } diff --git a/src/tests/helper.h b/src/tests/helper.h index 116b0d0..e208977 100644 --- a/src/tests/helper.h +++ b/src/tests/helper.h @@ -2,14 +2,16 @@ #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_SINGLE_SQL(query, stmt_type, stmt_class, output_var) \ - SQLStatementList* stmt_list = SQLParser::parseSQLString(query); \ - ASSERT(stmt_list->isValid); \ - ASSERT_EQ(stmt_list->numStatements(), 1); \ + 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); - #endif \ No newline at end of file diff --git a/src/tests/valid_queries.sql b/src/tests/valid_queries.sql index fde3ab3..11b9062 100644 --- a/src/tests/valid_queries.sql +++ b/src/tests/valid_queries.sql @@ -33,5 +33,6 @@ UPDATE students SET grade = 1.0; DROP TABLE students; # PREPARE PREPARE prep_inst: INSERT INTO test VALUES (?, ?, ?); +PREPARE prep2 { INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?, 0); INSERT INTO test VALUES (0, 0, ?); }; EXECUTE prep_inst(1, 2, 3); EXECUTE prep; \ No newline at end of file