added parsing of prepare and execute statement
This commit is contained in:
parent
6f1a2821b2
commit
21503300ca
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
|
@ -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,
|
kStmtDelete,
|
||||||
kStmtCreate,
|
kStmtCreate,
|
||||||
kStmtDrop,
|
kStmtDrop,
|
||||||
|
kStmtPrepare,
|
||||||
|
kStmtExecute,
|
||||||
// Following types are not supported yet
|
// Following types are not supported yet
|
||||||
kStmtExport,
|
kStmtExport,
|
||||||
kStmtRename,
|
kStmtRename,
|
||||||
|
|
|
@ -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 }
|
||||||
|
@ -105,6 +109,8 @@ typedef void* yyscan_t;
|
||||||
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++; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
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);
|
||||||
|
}
|
|
@ -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);
|
Loading…
Reference in New Issue