added parsing of prepare and execute statement

This commit is contained in:
Pedro 2014-12-15 16:43:32 +01:00
parent 6f1a2821b2
commit 21503300ca
10 changed files with 195 additions and 44 deletions

View File

@ -71,6 +71,7 @@ struct Expr {
char* alias; char* alias;
float fval; float fval;
int64_t ival; int64_t ival;
int64_t ival2;
OperatorType op_type; OperatorType op_type;
char op_char; char op_char;

View File

@ -74,6 +74,17 @@ ColumnDefinition::~ColumnDefinition() {
delete name; delete name;
} }
PrepareStatement::~PrepareStatement() {
delete stmt;
delete name;
}
ExecuteStatement::~ExecuteStatement() {
delete name;
delete parameters;
}
/** /**
* Table.h * Table.h
*/ */

View File

@ -9,5 +9,7 @@
#include "UpdateStatement.h" #include "UpdateStatement.h"
#include "DeleteStatement.h" #include "DeleteStatement.h"
#include "DropStatement.h" #include "DropStatement.h"
#include "PrepareStatement.h"
#include "ExecuteStatement.h"
#endif #endif

View File

@ -0,0 +1,29 @@
#ifndef __EXECUTE_STATEMENT_H__
#define __EXECUTE_STATEMENT_H__
#include "SQLStatement.h"
namespace hsql {
/**
* @struct ExecuteStatement
*
*/
struct ExecuteStatement : SQLStatement {
ExecuteStatement() :
SQLStatement(kStmtExecute),
name(NULL),
parameters(NULL) {}
virtual ~ExecuteStatement(); // defined in destructors.cpp
const char* name;
List<Expr*>* parameters;
};
} // namsepace hsql
#endif

View File

@ -0,0 +1,30 @@
#ifndef __PREPARE_STATEMENT_H__
#define __PREPARE_STATEMENT_H__
#include "SQLStatement.h"
#include "SelectStatement.h"
namespace hsql {
/**
* @struct PrepareStatement
*
*/
struct PrepareStatement : SQLStatement {
PrepareStatement() :
SQLStatement(kStmtPrepare),
name(NULL),
stmt(NULL) {}
virtual ~PrepareStatement(); // defined in destructors.cpp
const char* name;
SQLStatement* stmt;
};
} // namsepace hsql
#endif

View File

@ -19,6 +19,8 @@ typedef enum {
kStmtDelete, kStmtDelete,
kStmtCreate, kStmtCreate,
kStmtDrop, kStmtDrop,
kStmtPrepare,
kStmtExecute,
// Following types are not supported yet // Following types are not supported yet
kStmtExport, kStmtExport,
kStmtRename, kStmtRename,

View File

@ -31,12 +31,34 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
return 0; return 0;
} }
%} %}
/********************************* /*********************************
** Section 2: Bison Parser Declarations ** Section 2: Bison Parser Declarations
*********************************/ *********************************/
// Specify code that is included in the generated .h and .c files
%code requires {
// %code requires block
#include "parser_typedef.h"
// Auto update column and line number
#define YY_USER_ACTION \
yylloc->first_line = yylloc->last_line; \
yylloc->first_column = yylloc->last_column; \
for(int i = 0; yytext[i] != '\0'; i++) { \
if(yytext[i] == '\n') { \
yylloc->last_line++; \
yylloc->last_column = 0; \
} \
else { \
yylloc->last_column++; \
} \
}
}
// Define the names of the created files // Define the names of the created files
%output "bison_parser.cpp" %output "bison_parser.cpp"
%defines "bison_parser.h" %defines "bison_parser.h"
@ -51,33 +73,15 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
%define parse.error verbose %define parse.error verbose
%locations %locations
%initial-action {
// Initialize
@$.first_column = 0;
@$.last_column = 0;
@$.first_line = 0;
@$.last_line = 0;
@$.placeholder_id = 0;
};
// Specify code that is included in the generated .h and .c files
%code requires {
#ifndef YYtypeDEF_YY_SCANNER_T
#define YYtypeDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
#define YYSTYPE HSQL_STYPE
#define YYLTYPE HSQL_LTYPE
#define YY_USER_ACTION \
yylloc->first_line = yylloc->last_line; \
yylloc->first_column = yylloc->last_column; \
for(int i = 0; yytext[i] != '\0'; i++) { \
if(yytext[i] == '\n') { \
yylloc->last_line++; \
yylloc->last_column = 0; \
} \
else { \
yylloc->last_column++; \
} \
}
}
// Define additional parameters for yylex (http://www.gnu.org/software/bison/manual/html_node/Pure-Calling.html) // Define additional parameters for yylex (http://www.gnu.org/software/bison/manual/html_node/Pure-Calling.html)
%lex-param { yyscan_t scanner } %lex-param { yyscan_t scanner }
@ -98,13 +102,15 @@ typedef void* yyscan_t;
bool bval; bool bval;
hsql::SQLStatement* statement; hsql::SQLStatement* statement;
hsql::SelectStatement* select_stmt; hsql::SelectStatement* select_stmt;
hsql::ImportStatement* import_stmt; hsql::ImportStatement* import_stmt;
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::UpdateStatement* update_stmt;
hsql::DropStatement* drop_stmt; hsql::DropStatement* drop_stmt;
hsql::PrepareStatement* prep_stmt;
hsql::ExecuteStatement* exec_stmt;
hsql::TableRef* table; hsql::TableRef* table;
hsql::Expr* expr; hsql::Expr* expr;
@ -154,7 +160,8 @@ typedef void* yyscan_t;
*********************************/ *********************************/
%type <stmt_list> statement_list %type <stmt_list> statement_list
%type <statement> statement preparable_statement %type <statement> statement preparable_statement
%type <statement> prepare_statement execute_statement %type <exec_stmt> execute_statement
%type <prep_stmt> prepare_statement
%type <select_stmt> select_statement select_with_paren select_no_paren select_clause %type <select_stmt> select_statement select_with_paren select_no_paren select_clause
%type <import_stmt> import_statement %type <import_stmt> import_statement
%type <create_stmt> create_statement %type <create_stmt> create_statement
@ -222,7 +229,7 @@ statement_list:
statement: statement:
preparable_statement preparable_statement
| prepare_statement | prepare_statement { $$ = $1; }
; ;
@ -243,11 +250,19 @@ preparable_statement:
* Prepared Statement * Prepared Statement
******************************/ ******************************/
prepare_statement: prepare_statement:
PREPARE IDENTIFIER ':' preparable_statement { $$ = NULL; } PREPARE IDENTIFIER ':' preparable_statement {
$$ = new PrepareStatement();
$$->name = $2;
$$->stmt = $4;
}
; ;
execute_statement: execute_statement:
EXECUTE IDENTIFIER '(' literal_list ')' { $$ = NULL; } EXECUTE IDENTIFIER '(' literal_list ')' {
$$ = new ExecuteStatement();
$$->name = $2;
$$->parameters = $4;
}
; ;
@ -586,7 +601,7 @@ star_expr:
/* TODO: keep list of placeholders */ /* TODO: keep list of placeholders */
placeholder_expr: placeholder_expr:
'?' { $$ = new Expr(kExprPlaceholder); } '?' { $$ = new Expr(kExprPlaceholder); $$->ival = yylloc.placeholder_id++; }
; ;

View File

@ -0,0 +1,29 @@
#ifndef __PARSER_TYPEDEF_H__
#define __PARSER_TYPEDEF_H__
#ifndef YYtypeDEF_YY_SCANNER_T
#define YYtypeDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
#define YYSTYPE HSQL_STYPE
#define YYLTYPE HSQL_LTYPE
struct HSQL_CUST_LTYPE {
int first_line;
int first_column;
int last_line;
int last_column;
int placeholder_id;
};
#define HSQL_LTYPE HSQL_CUST_LTYPE
#define HSQL_LTYPE_IS_DECLARED 1
#endif

View File

@ -8,7 +8,16 @@
using namespace hsql; using namespace hsql;
TEST(Delete) { #define PARSE_SINGLE_SQL(query, stmt_type, stmt_class, output_var) \
SQLStatementList* stmt_list = SQLParser::parseSQLString(query); \
ASSERT(stmt_list->isValid); \
ASSERT_EQ(stmt_list->size(), 1); \
ASSERT_EQ(stmt_list->at(0)->type(), stmt_type); \
stmt_class* output_var = (stmt_class*) stmt_list->at(0);
TEST(DeleteStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); SQLStatementList* 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);
@ -22,7 +31,7 @@ TEST(Delete) {
ASSERT_EQ(stmt->expr->expr2->fval, 2.0); ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
} }
TEST(Create) { TEST(CreateStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)"); SQLStatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -44,7 +53,7 @@ TEST(Create) {
} }
TEST(Update) { TEST(UpdateStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';"); SQLStatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -72,7 +81,7 @@ TEST(Update) {
} }
TEST(Insert) { TEST(InsertStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)"); SQLStatementList* stmt_list = SQLParser::parseSQLString("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -82,7 +91,7 @@ TEST(Insert) {
} }
TEST(DropTable) { TEST(DropTableStatementTest) {
SQLStatementList* stmt_list = SQLParser::parseSQLString("DROP TABLE students"); SQLStatementList* stmt_list = SQLParser::parseSQLString("DROP TABLE students");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
@ -93,3 +102,26 @@ TEST(DropTable) {
ASSERT_NOTNULL(stmt->name); ASSERT_NOTNULL(stmt->name);
ASSERT_STREQ(stmt->name, "students"); ASSERT_STREQ(stmt->name, "students");
} }
TEST(PrepareStatementTest) {
PARSE_SINGLE_SQL("PREPARE test: SELECT ?, test FROM t2 WHERE c1 = ?;", kStmtPrepare, PrepareStatement, prep_stmt);
ASSERT_EQ(prep_stmt->stmt->type(), kStmtSelect);
ASSERT_STREQ(prep_stmt->name, "test");
SelectStatement* stmt = (SelectStatement*) prep_stmt->stmt;
ASSERT(stmt->select_list->at(0)->isType(kExprPlaceholder));
ASSERT(stmt->where_clause->expr2->isType(kExprPlaceholder));
// Check IDs of Placehoders
ASSERT_EQ(stmt->select_list->at(0)->ival, 0);
ASSERT_EQ(stmt->where_clause->expr2->ival, 1);
}
TEST(ExecuteStatementTest) {
PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, stmt);
ASSERT_STREQ(stmt->name, "test");
ASSERT_EQ(stmt->parameters->size(), 2);
}

View File

@ -31,5 +31,5 @@ UPDATE students SET grade = 1.0;
# DROP # DROP
DROP TABLE students; DROP TABLE students;
# PREPARE # PREPARE
PREPARE prep_inst: INSERT INTO test VALUES (?, ?, ?); SELECT * FROM test; PREPARE prep_inst: INSERT INTO test VALUES (?, ?, ?);
EXECUTE prep_inst(1, 2, 3); EXECUTE prep_inst(1, 2, 3);