added parsing of prepare and execute statement
This commit is contained in:
parent
6f1a2821b2
commit
21503300ca
|
@ -71,6 +71,7 @@ struct Expr {
|
|||
char* alias;
|
||||
float fval;
|
||||
int64_t ival;
|
||||
int64_t ival2;
|
||||
|
||||
OperatorType op_type;
|
||||
char op_char;
|
||||
|
|
|
@ -74,6 +74,17 @@ ColumnDefinition::~ColumnDefinition() {
|
|||
delete name;
|
||||
}
|
||||
|
||||
|
||||
PrepareStatement::~PrepareStatement() {
|
||||
delete stmt;
|
||||
delete name;
|
||||
}
|
||||
ExecuteStatement::~ExecuteStatement() {
|
||||
delete name;
|
||||
delete parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Table.h
|
||||
*/
|
||||
|
|
|
@ -9,5 +9,7 @@
|
|||
#include "UpdateStatement.h"
|
||||
#include "DeleteStatement.h"
|
||||
#include "DropStatement.h"
|
||||
#include "PrepareStatement.h"
|
||||
#include "ExecuteStatement.h"
|
||||
|
||||
#endif
|
|
@ -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
|
|
@ -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
|
|
@ -19,6 +19,8 @@ typedef enum {
|
|||
kStmtDelete,
|
||||
kStmtCreate,
|
||||
kStmtDrop,
|
||||
kStmtPrepare,
|
||||
kStmtExecute,
|
||||
// Following types are not supported yet
|
||||
kStmtExport,
|
||||
kStmtRename,
|
||||
|
|
|
@ -31,12 +31,34 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
%}
|
||||
/*********************************
|
||||
** 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
|
||||
%output "bison_parser.cpp"
|
||||
%defines "bison_parser.h"
|
||||
|
@ -51,33 +73,15 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
|||
%define parse.error verbose
|
||||
%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)
|
||||
%lex-param { yyscan_t scanner }
|
||||
|
@ -98,13 +102,15 @@ typedef void* yyscan_t;
|
|||
bool bval;
|
||||
|
||||
hsql::SQLStatement* statement;
|
||||
hsql::SelectStatement* select_stmt;
|
||||
hsql::ImportStatement* import_stmt;
|
||||
hsql::CreateStatement* create_stmt;
|
||||
hsql::InsertStatement* insert_stmt;
|
||||
hsql::DeleteStatement* delete_stmt;
|
||||
hsql::UpdateStatement* update_stmt;
|
||||
hsql::DropStatement* drop_stmt;
|
||||
hsql::SelectStatement* select_stmt;
|
||||
hsql::ImportStatement* import_stmt;
|
||||
hsql::CreateStatement* create_stmt;
|
||||
hsql::InsertStatement* insert_stmt;
|
||||
hsql::DeleteStatement* delete_stmt;
|
||||
hsql::UpdateStatement* update_stmt;
|
||||
hsql::DropStatement* drop_stmt;
|
||||
hsql::PrepareStatement* prep_stmt;
|
||||
hsql::ExecuteStatement* exec_stmt;
|
||||
|
||||
hsql::TableRef* table;
|
||||
hsql::Expr* expr;
|
||||
|
@ -154,7 +160,8 @@ typedef void* yyscan_t;
|
|||
*********************************/
|
||||
%type <stmt_list> statement_list
|
||||
%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 <import_stmt> import_statement
|
||||
%type <create_stmt> create_statement
|
||||
|
@ -222,7 +229,7 @@ statement_list:
|
|||
|
||||
statement:
|
||||
preparable_statement
|
||||
| prepare_statement
|
||||
| prepare_statement { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
|
@ -243,11 +250,19 @@ preparable_statement:
|
|||
* Prepared Statement
|
||||
******************************/
|
||||
prepare_statement:
|
||||
PREPARE IDENTIFIER ':' preparable_statement { $$ = NULL; }
|
||||
PREPARE IDENTIFIER ':' preparable_statement {
|
||||
$$ = new PrepareStatement();
|
||||
$$->name = $2;
|
||||
$$->stmt = $4;
|
||||
}
|
||||
;
|
||||
|
||||
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 */
|
||||
placeholder_expr:
|
||||
'?' { $$ = new Expr(kExprPlaceholder); }
|
||||
'?' { $$ = new Expr(kExprPlaceholder); $$->ival = yylloc.placeholder_id++; }
|
||||
;
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -8,7 +8,16 @@
|
|||
|
||||
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;");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->size(), 1);
|
||||
|
@ -22,7 +31,7 @@ TEST(Delete) {
|
|||
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)");
|
||||
ASSERT(stmt_list->isValid);
|
||||
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';");
|
||||
ASSERT(stmt_list->isValid);
|
||||
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)");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->size(), 1);
|
||||
|
@ -82,7 +91,7 @@ TEST(Insert) {
|
|||
}
|
||||
|
||||
|
||||
TEST(DropTable) {
|
||||
TEST(DropTableStatementTest) {
|
||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("DROP TABLE students");
|
||||
ASSERT(stmt_list->isValid);
|
||||
ASSERT_EQ(stmt_list->size(), 1);
|
||||
|
@ -92,4 +101,27 @@ TEST(DropTable) {
|
|||
ASSERT_EQ(stmt->type, DropStatement::kTable);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
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);
|
||||
}
|
|
@ -31,5 +31,5 @@ UPDATE students SET grade = 1.0;
|
|||
# DROP
|
||||
DROP TABLE students;
|
||||
# PREPARE
|
||||
PREPARE prep_inst: INSERT INTO test VALUES (?, ?, ?); SELECT * FROM test;
|
||||
PREPARE prep_inst: INSERT INTO test VALUES (?, ?, ?);
|
||||
EXECUTE prep_inst(1, 2, 3);
|
Loading…
Reference in New Issue