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;
|
||||
}
|
||||
|
||||
Expr* Expr::makePlaceholder(int id) {
|
||||
Expr* e = new Expr(kExprPlaceholder);
|
||||
e->ival = id;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr::~Expr() {
|
||||
delete expr;
|
||||
delete expr2;
|
||||
|
|
|
@ -112,6 +112,8 @@ struct Expr {
|
|||
static Expr* makeColumnRef(char* name);
|
||||
static Expr* makeColumnRef(char* table, char* name);
|
||||
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
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "SQLStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
@ -15,15 +16,34 @@ struct PrepareStatement : SQLStatement {
|
|||
PrepareStatement() :
|
||||
SQLStatement(kStmtPrepare),
|
||||
name(NULL),
|
||||
stmt(NULL) {}
|
||||
query(NULL) {}
|
||||
|
||||
virtual ~PrepareStatement() {
|
||||
delete stmt;
|
||||
delete query;
|
||||
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;
|
||||
SQLStatement* stmt;
|
||||
SQLStatementList* query;
|
||||
std::vector<Expr*> placeholders;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#define __STATEMENT_H__
|
||||
|
||||
#include "List.h"
|
||||
#include "Expr.h"
|
||||
#include <vector>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
@ -63,7 +65,7 @@ public:
|
|||
virtual ~SQLStatementList() {
|
||||
delete parser_msg;
|
||||
}
|
||||
|
||||
|
||||
bool isValid;
|
||||
const char* parser_msg;
|
||||
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_column = yylloc->last_column; \
|
||||
for(int i = 0; yytext[i] != '\0'; i++) { \
|
||||
yylloc->total_column++; \
|
||||
if(yytext[i] == '\n') { \
|
||||
yylloc->last_line++; \
|
||||
yylloc->last_column = 0; \
|
||||
|
@ -79,6 +80,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
|||
@$.last_column = 0;
|
||||
@$.first_line = 0;
|
||||
@$.last_line = 0;
|
||||
@$.total_column = 0;
|
||||
@$.placeholder_id = 0;
|
||||
};
|
||||
|
||||
|
@ -220,7 +222,13 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
|||
|
||||
// Defines our general 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:
|
||||
preparable_statement
|
||||
| prepare_statement { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
|
@ -252,10 +259,10 @@ preparable_statement:
|
|||
* Prepared Statement
|
||||
******************************/
|
||||
prepare_statement:
|
||||
PREPARE IDENTIFIER ':' preparable_statement {
|
||||
PREPARE IDENTIFIER ':' statement_list opt_semicolon {
|
||||
$$ = new PrepareStatement();
|
||||
$$->name = $2;
|
||||
$$->stmt = $4;
|
||||
$$->query = $4;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -615,7 +622,10 @@ star_expr:
|
|||
|
||||
/* TODO: keep list of placeholders */
|
||||
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__
|
||||
#define __PARSER_TYPEDEF_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifndef YYtypeDEF_YY_SCANNER_T
|
||||
#define YYtypeDEF_YY_SCANNER_T
|
||||
|
@ -17,7 +19,12 @@ struct HSQL_CUST_LTYPE {
|
|||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
|
||||
int total_column;
|
||||
|
||||
// Placeholder
|
||||
int placeholder_id;
|
||||
std::vector<void*> placeholder_list;
|
||||
};
|
||||
|
||||
#define HSQL_LTYPE HSQL_CUST_LTYPE
|
||||
|
|
|
@ -98,17 +98,36 @@ TEST(DropTableStatementTest) {
|
|||
|
||||
|
||||
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_EQ(prep_stmt->placeholders.size(), 3);
|
||||
|
||||
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);
|
||||
|
||||
ASSERT_EQ(prep_stmt->query->size(), 2);
|
||||
ASSERT_EQ(prep_stmt->query->at(0)->type(), kStmtInsert);
|
||||
ASSERT_EQ(prep_stmt->query->at(1)->type(), kStmtSelect);
|
||||
|
||||
|
||||
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