added update statement support

This commit is contained in:
Pedro 2014-12-02 01:27:02 +01:00
parent 2f76183586
commit 03fe3a69e2
10 changed files with 121 additions and 10 deletions

View File

@ -36,3 +36,8 @@ clean:
rm -f *.o *~ $(BIN_DIR)/analysis $(TESTS_BIN) $(BIN_DIR)/grammar_test $(BIN_DIR)/tests rm -f *.o *~ $(BIN_DIR)/analysis $(TESTS_BIN) $(BIN_DIR)/grammar_test $(BIN_DIR)/tests
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
make clean -C parser/ make clean -C parser/
test: tests grammar_test
@./$(BIN_DIR)/grammar_test -f ../test/valid_queries.sql
@./$(BIN_DIR)/tests

View File

@ -20,7 +20,7 @@ struct UpdateStatement : Statement {
virtual ~UpdateStatement(); // defined in destructors.cpp virtual ~UpdateStatement(); // defined in destructors.cpp
TableRef* table; TableRef* table;
List<UpdateClause*> updates; List<UpdateClause*>* updates;
Expr* where; Expr* where;
}; };

View File

@ -38,6 +38,15 @@ DeleteStatement::~DeleteStatement() {
delete expr; delete expr;
} }
/**
* UpdateStatement.h
*/
UpdateStatement::~UpdateStatement() {
delete table;
delete updates;
delete where;
}
/** /**
* SelectStatement.h * SelectStatement.h
*/ */

View File

@ -5,7 +5,6 @@
namespace hsql { namespace hsql {
void printExpression(Expr* expr, uint num_indent);
void printOperatorExpression(Expr* expr, uint num_indent); void printOperatorExpression(Expr* expr, uint num_indent);
const char* indent(uint num_indent) { return std::string(num_indent, '\t').c_str(); } const char* indent(uint num_indent) { return std::string(num_indent, '\t').c_str(); }

View File

@ -11,6 +11,7 @@ void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
void printImportStatementInfo(ImportStatement* stmt, uint num_indent); void printImportStatementInfo(ImportStatement* stmt, uint num_indent);
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent); void printInsertStatementInfo(InsertStatement* stmt, uint num_indent);
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent); void printCreateStatementInfo(CreateStatement* stmt, uint num_indent);
void printExpression(Expr* expr, uint num_indent);
} // namespace hsql } // namespace hsql

View File

@ -84,6 +84,7 @@ typedef void* yyscan_t;
hsql::CreateStatement* create_stmt; hsql::CreateStatement* create_stmt;
hsql::InsertStatement* insert_stmt; hsql::InsertStatement* insert_stmt;
hsql::DeleteStatement* delete_stmt; hsql::DeleteStatement* delete_stmt;
hsql::UpdateStatement* update_stmt;
hsql::TableRef* table; hsql::TableRef* table;
hsql::Expr* expr; hsql::Expr* expr;
@ -91,12 +92,14 @@ typedef void* yyscan_t;
hsql::OrderType order_type; hsql::OrderType order_type;
hsql::LimitDescription* limit; hsql::LimitDescription* limit;
hsql::ColumnDefinition* column_t; hsql::ColumnDefinition* column_t;
hsql::UpdateClause* update_t;
hsql::StatementList* stmt_list; hsql::StatementList* stmt_list;
hsql::List<char*>* slist; hsql::List<char*>* slist;
hsql::List<hsql::Expr*>* expr_list; hsql::List<hsql::Expr*>* expr_list;
hsql::List<hsql::TableRef*>* table_list; hsql::List<hsql::TableRef*>* table_list;
hsql::List<hsql::ColumnDefinition*>* column_list_t; hsql::List<hsql::ColumnDefinition*>* column_list_t;
hsql::List<hsql::UpdateClause*>* update_list_t;
} }
@ -135,11 +138,12 @@ typedef void* yyscan_t;
%type <create_stmt> create_statement %type <create_stmt> create_statement
%type <insert_stmt> insert_statement %type <insert_stmt> insert_statement
%type <delete_stmt> delete_statement truncate_statement %type <delete_stmt> delete_statement truncate_statement
%type <update_stmt> update_statement
%type <sval> table_name opt_alias alias file_path %type <sval> table_name opt_alias alias file_path
%type <bval> opt_not_exists %type <bval> opt_not_exists
%type <uval> import_file_type opt_join_type column_type %type <uval> import_file_type opt_join_type column_type
%type <table> from_clause table_ref table_ref_atomic table_ref_name %type <table> from_clause table_ref table_ref_atomic table_ref_name
%type <table> join_clause join_table %type <table> join_clause join_table table_ref_name_no_alias
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias %type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias
%type <expr> column_name literal int_literal num_literal string_literal %type <expr> column_name literal int_literal num_literal string_literal
%type <expr> comp_expr opt_where join_condition %type <expr> comp_expr opt_where join_condition
@ -151,6 +155,8 @@ typedef void* yyscan_t;
%type <slist> ident_commalist opt_column_list %type <slist> ident_commalist opt_column_list
%type <column_t> column_def %type <column_t> column_def
%type <column_list_t> column_def_commalist %type <column_list_t> column_def_commalist
%type <update_t> update_clause
%type <update_list_t> update_clause_commalist
/****************************** /******************************
** Token Precedence and Associativity ** Token Precedence and Associativity
@ -198,6 +204,7 @@ statement:
| insert_statement { $$ = $1; } | insert_statement { $$ = $1; }
| delete_statement { $$ = $1; } | delete_statement { $$ = $1; }
| truncate_statement { $$ = $1; } | truncate_statement { $$ = $1; }
| update_statement { $$ = $1; }
; ;
@ -316,6 +323,34 @@ opt_column_list:
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;
/******************************
* Update Statement
* UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann';
******************************/
update_statement:
UPDATE table_ref_name_no_alias SET update_clause_commalist opt_where {
$$ = new UpdateStatement();
$$->table = $2;
$$->updates = $4;
$$->where = $5;
}
;
update_clause_commalist:
update_clause { $$ = new List<UpdateClause*>($1); }
| update_clause_commalist ',' update_clause { $1->push_back($3); $$ = $1; }
;
update_clause:
IDENTIFIER '=' literal {
$$ = new UpdateClause();
$$->column = $1;
$$->value = $3;
}
;
/****************************** /******************************
* Select Statement * Select Statement
******************************/ ******************************/
@ -539,7 +574,16 @@ table_ref_name:
tbl->alias = $2; tbl->alias = $2;
$$ = tbl; $$ = tbl;
} }
; ;
table_ref_name_no_alias:
table_name {
$$ = new TableRef(kTableName);
$$->name = $1;
}
;
table_name: table_name:
IDENTIFIER IDENTIFIER

View File

@ -86,9 +86,9 @@ int main(int argc, char *argv[]) {
} }
if (num_failed == 0) { if (num_failed == 0) {
printf("All %lu grammar tests completed successfully!\n", queries.size()); printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
} else { } else {
fprintf(stderr, "Some grammar tests failed! %d out of %lu tests failed!\n", num_failed, queries.size()); fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", num_failed, queries.size());
} }

View File

@ -3,14 +3,16 @@
*/ */
#include "SQLParser.h" #include "SQLParser.h"
#include "sqlhelper.h"
#include "tests/test.h" #include "tests/test.h"
using namespace hsql; using namespace hsql;
TEST(SelectTest) { TEST(Select) {
StatementList* stmt_list = SQLParser::parseSQLString("SELECT * FROM students;"); StatementList* stmt_list = SQLParser::parseSQLString("SELECT * FROM students;");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -21,7 +23,7 @@ TEST(SelectTest) {
} }
TEST(DeleteTest) { TEST(Delete) {
StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -35,7 +37,7 @@ TEST(DeleteTest) {
ASSERT_EQ(stmt->expr->expr2->fval, 2.0); ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
} }
TEST(CreateTable) { TEST(Create) {
StatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"); StatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -50,4 +52,42 @@ TEST(CreateTable) {
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT); ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
ASSERT_STREQ(stmt->columns->at(3)->name, "grade"); ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE); ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
}
TEST(Update) {
StatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1);
ASSERT_EQ(stmt_list->at(0)->type, kStmtUpdate);
UpdateStatement* stmt = (UpdateStatement*) stmt_list->at(0);
ASSERT_NOTNULL(stmt->table);
ASSERT_STREQ(stmt->table->name, "students");
ASSERT_NOTNULL(stmt->updates);
ASSERT_EQ(stmt->updates->size(), 2);
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
ASSERT_NOTNULL(stmt->where);
ASSERT(stmt->where->isType(kExprOperator));
ASSERT(stmt->where->isSimpleOp('='));
ASSERT_STREQ(stmt->where->expr->name, "name");
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");
}
TEST(Insert) {
StatementList* stmt_list = SQLParser::parseSQLString("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)");
ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1);
ASSERT_EQ(stmt_list->at(0)->type, kStmtInsert);
// TODO
} }

View File

@ -1,11 +1,16 @@
#ifndef __TEST_H__ #ifndef __TEST_H__
#define __TEST_H__ #define __TEST_H__
#include <iostream>
#define TEST(name) \ #define TEST(name) \
void name(); \ void name(); \
namespace g_dummy { int _##name = AddTest(name, #name); } \ namespace g_dummy { int _##name = AddTest(name, #name); } \
void name() void name()
#define ASSERT(cond) if (!(cond)) throw AssertionFailedException(#cond); #define ASSERT(cond) if (!(cond)) throw AssertionFailedException(#cond);
#define ASSERT_TRUE(cond) ASSERT(cond); #define ASSERT_TRUE(cond) ASSERT(cond);
@ -17,7 +22,11 @@
#define ASSERT_STREQ(a, b) \ #define ASSERT_STREQ(a, b) \
if (std::string(a).compare(std::string(b)) != 0) throw AssertionFailedException(#a " == " #b) if (std::string(a).compare(std::string(b)) != 0) throw AssertionFailedException(#a " == " #b)
#define ASSERT_EQ(a, b) \ #define ASSERT_EQ(a, b) \
if (a != b) { \
std::cout << "Actual values: " << a << " != " << b << std::endl; \
} \
ASSERT(a == b); ASSERT(a == b);
class AssertionFailedException: public std::exception { class AssertionFailedException: public std::exception {

View File

@ -23,4 +23,8 @@ INSERT INTO test_table SELECT * FROM students;
# DELETE # DELETE
DELETE FROM students WHERE grade > 3.0 DELETE FROM students WHERE grade > 3.0
DELETE FROM students DELETE FROM students
TRUNCATE students TRUNCATE students
# UPDATE
UPDATE students SET grade = 1.3 WHERE name = 'Max Mustermann';
UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann';
UPDATE students SET grade = 1.0;