improved prepared statements
This commit is contained in:
parent
8abfd6094e
commit
fed174a892
|
@ -86,6 +86,12 @@ Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makePlaceholder(int id) {
|
||||||
|
Expr* e = new Expr(kExprPlaceholder);
|
||||||
|
e->ival = id;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
Expr::~Expr() {
|
Expr::~Expr() {
|
||||||
delete expr;
|
delete expr;
|
||||||
delete expr2;
|
delete expr2;
|
||||||
|
|
|
@ -112,6 +112,8 @@ struct Expr {
|
||||||
static Expr* makeColumnRef(char* name);
|
static Expr* makeColumnRef(char* name);
|
||||||
static Expr* makeColumnRef(char* table, char* name);
|
static Expr* makeColumnRef(char* table, char* name);
|
||||||
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
|
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
|
||||||
|
|
||||||
|
static Expr* makePlaceholder(int id);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zero initializes an Expr object and assigns it to a space in the heap
|
// Zero initializes an Expr object and assigns it to a space in the heap
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
#include "SelectStatement.h"
|
#include "SelectStatement.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
@ -15,15 +16,34 @@ struct PrepareStatement : SQLStatement {
|
||||||
PrepareStatement() :
|
PrepareStatement() :
|
||||||
SQLStatement(kStmtPrepare),
|
SQLStatement(kStmtPrepare),
|
||||||
name(NULL),
|
name(NULL),
|
||||||
stmt(NULL) {}
|
query(NULL) {}
|
||||||
|
|
||||||
virtual ~PrepareStatement() {
|
virtual ~PrepareStatement() {
|
||||||
delete stmt;
|
delete query;
|
||||||
delete name;
|
delete name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param vector of placeholders that the parser found
|
||||||
|
*
|
||||||
|
* When setting the placeholders we need to make sure that they are in the correct order.
|
||||||
|
* To ensure that, during parsing we store the character position use that to sort the list here.
|
||||||
|
*/
|
||||||
|
void setPlaceholders(std::vector<void*> ph) {
|
||||||
|
for (void* e : ph) {
|
||||||
|
if (e != NULL)
|
||||||
|
placeholders.push_back((Expr*) e);
|
||||||
|
}
|
||||||
|
// Sort by col-id
|
||||||
|
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
||||||
|
|
||||||
|
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||||
|
for (uint i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||||
|
}
|
||||||
|
|
||||||
const char* name;
|
const char* name;
|
||||||
SQLStatement* stmt;
|
SQLStatementList* query;
|
||||||
|
std::vector<Expr*> placeholders;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#define __STATEMENT_H__
|
#define __STATEMENT_H__
|
||||||
|
|
||||||
#include "List.h"
|
#include "List.h"
|
||||||
|
#include "Expr.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ public:
|
||||||
virtual ~SQLStatementList() {
|
virtual ~SQLStatementList() {
|
||||||
delete parser_msg;
|
delete parser_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValid;
|
bool isValid;
|
||||||
const char* parser_msg;
|
const char* parser_msg;
|
||||||
int error_line;
|
int error_line;
|
||||||
|
|
|
@ -49,6 +49,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
yylloc->first_line = yylloc->last_line; \
|
yylloc->first_line = yylloc->last_line; \
|
||||||
yylloc->first_column = yylloc->last_column; \
|
yylloc->first_column = yylloc->last_column; \
|
||||||
for(int i = 0; yytext[i] != '\0'; i++) { \
|
for(int i = 0; yytext[i] != '\0'; i++) { \
|
||||||
|
yylloc->total_column++; \
|
||||||
if(yytext[i] == '\n') { \
|
if(yytext[i] == '\n') { \
|
||||||
yylloc->last_line++; \
|
yylloc->last_line++; \
|
||||||
yylloc->last_column = 0; \
|
yylloc->last_column = 0; \
|
||||||
|
@ -79,6 +80,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
@$.last_column = 0;
|
@$.last_column = 0;
|
||||||
@$.first_line = 0;
|
@$.first_line = 0;
|
||||||
@$.last_line = 0;
|
@$.last_line = 0;
|
||||||
|
@$.total_column = 0;
|
||||||
@$.placeholder_id = 0;
|
@$.placeholder_id = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -220,7 +222,13 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
|
|
||||||
// Defines our general input.
|
// Defines our general input.
|
||||||
input:
|
input:
|
||||||
statement_list opt_semicolon { *result = $1; }
|
prepare_statement {
|
||||||
|
$1->setPlaceholders(yyloc.placeholder_list);
|
||||||
|
*result = new SQLStatementList($1);
|
||||||
|
}
|
||||||
|
| statement_list opt_semicolon {
|
||||||
|
*result = $1;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,7 +239,6 @@ statement_list:
|
||||||
|
|
||||||
statement:
|
statement:
|
||||||
preparable_statement
|
preparable_statement
|
||||||
| prepare_statement { $$ = $1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,10 +259,10 @@ preparable_statement:
|
||||||
* Prepared Statement
|
* Prepared Statement
|
||||||
******************************/
|
******************************/
|
||||||
prepare_statement:
|
prepare_statement:
|
||||||
PREPARE IDENTIFIER ':' preparable_statement {
|
PREPARE IDENTIFIER ':' statement_list opt_semicolon {
|
||||||
$$ = new PrepareStatement();
|
$$ = new PrepareStatement();
|
||||||
$$->name = $2;
|
$$->name = $2;
|
||||||
$$->stmt = $4;
|
$$->query = $4;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -615,7 +622,10 @@ star_expr:
|
||||||
|
|
||||||
/* TODO: keep list of placeholders */
|
/* TODO: keep list of placeholders */
|
||||||
placeholder_expr:
|
placeholder_expr:
|
||||||
'?' { $$ = new Expr(kExprPlaceholder); $$->ival = yylloc.placeholder_id++; }
|
'?' {
|
||||||
|
$$ = Expr::makePlaceholder(yylloc.total_column);
|
||||||
|
yyloc.placeholder_list.push_back($$);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef __PARSER_TYPEDEF_H__
|
#ifndef __PARSER_TYPEDEF_H__
|
||||||
#define __PARSER_TYPEDEF_H__
|
#define __PARSER_TYPEDEF_H__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
#ifndef YYtypeDEF_YY_SCANNER_T
|
#ifndef YYtypeDEF_YY_SCANNER_T
|
||||||
#define YYtypeDEF_YY_SCANNER_T
|
#define YYtypeDEF_YY_SCANNER_T
|
||||||
|
@ -17,7 +19,12 @@ struct HSQL_CUST_LTYPE {
|
||||||
int first_column;
|
int first_column;
|
||||||
int last_line;
|
int last_line;
|
||||||
int last_column;
|
int last_column;
|
||||||
|
|
||||||
|
int total_column;
|
||||||
|
|
||||||
|
// Placeholder
|
||||||
int placeholder_id;
|
int placeholder_id;
|
||||||
|
std::vector<void*> placeholder_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HSQL_LTYPE HSQL_CUST_LTYPE
|
#define HSQL_LTYPE HSQL_CUST_LTYPE
|
||||||
|
|
|
@ -98,17 +98,36 @@ TEST(DropTableStatementTest) {
|
||||||
|
|
||||||
|
|
||||||
TEST(PrepareStatementTest) {
|
TEST(PrepareStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("PREPARE test: SELECT ?, test FROM t2 WHERE c1 = ?;", kStmtPrepare, PrepareStatement, prep_stmt);
|
TEST_PARSE_SINGLE_SQL("PREPARE test:"
|
||||||
|
"INSERT INTO test VALUES(?);"
|
||||||
|
"SELECT ?, test FROM test WHERE c1 = ?;"
|
||||||
|
"", kStmtPrepare, PrepareStatement, prep_stmt);
|
||||||
|
|
||||||
ASSERT_EQ(prep_stmt->stmt->type(), kStmtSelect);
|
|
||||||
ASSERT_STREQ(prep_stmt->name, "test");
|
ASSERT_STREQ(prep_stmt->name, "test");
|
||||||
|
ASSERT_EQ(prep_stmt->placeholders.size(), 3);
|
||||||
|
|
||||||
SelectStatement* stmt = (SelectStatement*) prep_stmt->stmt;
|
|
||||||
ASSERT(stmt->select_list->at(0)->isType(kExprPlaceholder));
|
ASSERT_EQ(prep_stmt->query->size(), 2);
|
||||||
ASSERT(stmt->where_clause->expr2->isType(kExprPlaceholder));
|
ASSERT_EQ(prep_stmt->query->at(0)->type(), kStmtInsert);
|
||||||
// Check IDs of Placehoders
|
ASSERT_EQ(prep_stmt->query->at(1)->type(), kStmtSelect);
|
||||||
ASSERT_EQ(stmt->select_list->at(0)->ival, 0);
|
|
||||||
ASSERT_EQ(stmt->where_clause->expr2->ival, 1);
|
|
||||||
|
InsertStatement* insert = (InsertStatement*) prep_stmt->query->at(0);
|
||||||
|
SelectStatement* select = (SelectStatement*) prep_stmt->query->at(1);
|
||||||
|
|
||||||
|
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||||
|
ASSERT(select->select_list->at(0)->isType(kExprPlaceholder));
|
||||||
|
ASSERT(select->where_clause->expr2->isType(kExprPlaceholder));
|
||||||
|
|
||||||
|
// Check IDs of placeholders
|
||||||
|
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||||
|
ASSERT_EQ(insert->values->at(0), prep_stmt->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->where_clause->expr2->ival, 2);
|
||||||
|
ASSERT_EQ(select->where_clause->expr2, prep_stmt->placeholders[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue