Merge pull request #34 from torpedro/misc

Interface Improvements
This commit is contained in:
Pedro Flemming 2017-04-14 15:15:23 +02:00 committed by GitHub
commit 9184d5d0c2
33 changed files with 927 additions and 816 deletions

View File

@ -1,4 +1,7 @@
SRC = ./
CPP = $(shell find $(SRC) -name '*.cpp')
CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../ CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../
all: parser_benchmark all: parser_benchmark
@ -6,8 +9,8 @@ all: parser_benchmark
run: parser_benchmark run: parser_benchmark
@export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../ && ./parser_benchmark @export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../ && ./parser_benchmark
parser_benchmark: parser_benchmark.cpp parser_benchmark: $(CPP)
$(CXX) $(CFLAGS) parser_benchmark.cpp -o parser_benchmark -lbenchmark -lpthread -lsqlparser $(CXX) $(CFLAGS) $(CPP) -o parser_benchmark -lbenchmark -lpthread -lsqlparser
clean: clean:
rm -f parser_benchmark rm -f parser_benchmark

View File

@ -31,6 +31,18 @@ PARSE_QUERY_BENCHMARK(BM_LongSelectElement26,
PARSE_QUERY_BENCHMARK(BM_LongSelectElement52, PARSE_QUERY_BENCHMARK(BM_LongSelectElement52,
"SELECT aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa FROM test;"); "SELECT aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa FROM test;");
// Prepare and Execute benchmarks.
PARSE_QUERY_BENCHMARK(BM_ExecuteStatement,
"EXECUTE procedure;");
PARSE_QUERY_BENCHMARK(BM_ExecuteWith2ParametersStatement,
"EXECUTE procedure(11, 'test');");
PARSE_QUERY_BENCHMARK(BM_ExecuteWith10ParametersStatement,
"EXECUTE procedure(11, 'test', 5.6, 4.2, 'abc', 6, 7, 8, 9, 10000);");
// Benchmark the influence of increasing size of the query, while // Benchmark the influence of increasing size of the query, while
// the number of tokens remains unchanged. // the number of tokens remains unchanged.
static void BM_CharacterCount(benchmark::State& st) { static void BM_CharacterCount(benchmark::State& st) {

View File

@ -6,7 +6,7 @@
#include "SQLParser.h" #include "SQLParser.h"
// contains printing utilities // contains printing utilities
#include "sqlhelper.h" #include "util/sqlhelper.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc <= 1) { if (argc <= 1) {
@ -16,31 +16,26 @@ int main(int argc, char *argv[]) {
std::string query = argv[1]; std::string query = argv[1];
// parse a given query // parse a given query
hsql::SQLParserResult* result = hsql::SQLParser::parseSQLString(query); hsql::SQLParserResult result;
hsql::SQLParser::parseSQLString(query, &result);
// check whether the parsing was successful // check whether the parsing was successful
if (!result) {
return -1;
}
if (result->isValid()) { if (result.isValid()) {
printf("Parsed successfully!\n"); printf("Parsed successfully!\n");
printf("Number of statements: %lu\n", result->size()); printf("Number of statements: %lu\n", result.size());
for (uint i = 0; i < result->size(); ++i) { for (uint i = 0; i < result.size(); ++i) {
// Print a statement summary. // Print a statement summary.
hsql::printStatementInfo(result->getStatement(i)); hsql::printStatementInfo(result.getStatement(i));
} }
delete result;
return 0; return 0;
} else { } else {
fprintf(stderr, "Given string is not a valid SQL query.\n"); fprintf(stderr, "Given string is not a valid SQL query.\n");
fprintf(stderr, "%s (L%d:%d)\n", fprintf(stderr, "%s (L%d:%d)\n",
result->errorMsg(), result.errorMsg(),
result->errorLine(), result.errorLine(),
result->errorColumn()); result.errorColumn());
delete result;
return -1; return -1;
} }
} }

View File

@ -12,36 +12,51 @@ namespace hsql {
fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n"); fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n");
} }
SQLParserResult* SQLParser::parseSQLString(const char* text) { // static
SQLParserResult* result = NULL; bool SQLParser::parseSQLString(const char* text, SQLParserResult* result) {
yyscan_t scanner; yyscan_t scanner;
YY_BUFFER_STATE state; YY_BUFFER_STATE state;
if (hsql_lex_init(&scanner)) { if (hsql_lex_init(&scanner)) {
// Couldn't initialize the lexer. // Couldn't initialize the lexer.
fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n"); fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n");
return NULL; return false;
} }
state = hsql__scan_string(text, scanner); state = hsql__scan_string(text, scanner);
// Parser and return early if it failed. // Parse the tokens.
if (hsql_parse(&result, scanner)) { // If parsing fails, the result will contain an error object.
// Returns an error stmt object. int ret = hsql_parse(result, scanner);
hsql__delete_buffer(state, scanner); bool success = (ret == 0);
hsql_lex_destroy(scanner); result->setIsValid(success);
return result;
}
hsql__delete_buffer(state, scanner); hsql__delete_buffer(state, scanner);
hsql_lex_destroy(scanner); hsql_lex_destroy(scanner);
return true;
}
// static
bool SQLParser::parseSQLString(const std::string& text, SQLParserResult* result) {
return parseSQLString(text.c_str(), result);
}
// static
SQLParserResult* SQLParser::parseSQLString(const char* text) {
SQLParserResult* result = new SQLParserResult();
if (!SQLParser::parseSQLString(text, result)) {
delete result;
return NULL;
}
return result; return result;
} }
// static
SQLParserResult* SQLParser::parseSQLString(const std::string& text) { SQLParserResult* SQLParser::parseSQLString(const std::string& text) {
return parseSQLString(text.c_str()); return parseSQLString(text.c_str());
} }
} // namespace hsql } // namespace hsql

View File

@ -1,5 +1,5 @@
#ifndef __SQLPARSER_H_ #ifndef __SQLPARSER__SQLPARSER_H__
#define __SQLPARSER_H_ #define __SQLPARSER__SQLPARSER_H__
#include "SQLParserResult.h" #include "SQLParserResult.h"
#include "sql/statements.h" #include "sql/statements.h"
@ -9,10 +9,25 @@ namespace hsql {
// Static methods used to parse SQL strings. // Static methods used to parse SQL strings.
class SQLParser { class SQLParser {
public: public:
// Parses a given constant character SQL string into the result object.
// Returns true if the lexer and parser could run without internal errors.
// This does NOT mean that the SQL string was valid SQL. To check that
// you need to check result->isValid();
static bool parseSQLString(const char* sql, SQLParserResult* result);
// Parses a given SQL string into the result object.
static bool parseSQLString(const std::string& sql, SQLParserResult* result);
// Deprecated:
// Parses a given constant character SQL string. // Parses a given constant character SQL string.
// Note: This is kept for legacy reasons. It is recommended to use
// the (const char*, SQLParserResult*) implementation.
static SQLParserResult* parseSQLString(const char* sql); static SQLParserResult* parseSQLString(const char* sql);
// Deprecated:
// Parses an SQL std::string. // Parses an SQL std::string.
// Note: This is kept for legacy reasons. It is recommended to use
// the (const std::string&, SQLParserResult*) implementation.
static SQLParserResult* parseSQLString(const std::string& sql); static SQLParserResult* parseSQLString(const std::string& sql);
private: private:

View File

@ -4,21 +4,17 @@
namespace hsql { namespace hsql {
SQLParserResult::SQLParserResult() : SQLParserResult::SQLParserResult() :
isValid_(true), isValid_(false),
errorMsg_(NULL) {}; errorMsg_(NULL) {};
SQLParserResult::SQLParserResult(SQLStatement* stmt) : SQLParserResult::SQLParserResult(SQLStatement* stmt) :
isValid_(true), isValid_(false),
errorMsg_(NULL) { errorMsg_(NULL) {
addStatement(stmt); addStatement(stmt);
}; };
SQLParserResult::~SQLParserResult() { SQLParserResult::~SQLParserResult() {
for (SQLStatement* statement : statements_) { reset();
delete statement;
}
free(errorMsg_);
} }
void SQLParserResult::addStatement(SQLStatement* stmt) { void SQLParserResult::addStatement(SQLStatement* stmt) {
@ -63,4 +59,30 @@ namespace hsql {
errorColumn_ = errorColumn; errorColumn_ = errorColumn;
} }
const std::vector<SQLStatement*>& SQLParserResult::getStatements() const {
return statements_;
}
std::vector<SQLStatement*> SQLParserResult::releaseStatements() {
std::vector<SQLStatement*> copy = statements_;
statements_.clear();
return copy;
}
void SQLParserResult::reset() {
for (SQLStatement* statement : statements_) {
delete statement;
}
statements_.clear();
isValid_ = false;
free(errorMsg_);
errorMsg_ = NULL;
errorLine_ = -1;
errorColumn_ = -1;
}
} // namespace hsql } // namespace hsql

View File

@ -1,5 +1,5 @@
#ifndef __SQLPARSERRESULT__ #ifndef __SQLPARSER__SQLPARSER_RESULT_H__
#define __SQLPARSERRESULT__ #define __SQLPARSER__SQLPARSER_RESULT_H__
#include "sql/SQLStatement.h" #include "sql/SQLStatement.h"
@ -15,15 +15,22 @@ namespace hsql {
// Takes ownership of the statement. // Takes ownership of the statement.
SQLParserResult(SQLStatement* stmt); SQLParserResult(SQLStatement* stmt);
// Deletes all statements in the resul. // Deletes all statements in the result.
virtual ~SQLParserResult(); virtual ~SQLParserResult();
// Set whether parsing was successful.
void setIsValid(bool isValid);
// Returns true if parsing was successful. // Returns true if parsing was successful.
bool isValid() const; bool isValid() const;
// Returns the number of statements in the result. // Returns the number of statements in the result.
size_t size() const; size_t size() const;
// Set the details of the error, if available.
// Takes ownership of errorMsg.
void setErrorDetails(char* errorMsg, int errorLine, int errorColumn);
// Returns the error message, if an error occurred. // Returns the error message, if an error occurred.
const char* errorMsg() const; const char* errorMsg() const;
@ -33,23 +40,25 @@ namespace hsql {
// Returns the column number of the occurrance of the error in the query. // Returns the column number of the occurrance of the error in the query.
int errorColumn() const; int errorColumn() const;
// Adds a statement to the result list of statements.
// SQLParserResult takes ownership of the statement.
void addStatement(SQLStatement* stmt);
// Gets the SQL statement with the given index. // Gets the SQL statement with the given index.
const SQLStatement* getStatement(int index) const; const SQLStatement* getStatement(int index) const;
// Gets the non const SQL statement with the given index. // Gets the non const SQL statement with the given index.
SQLStatement* getMutableStatement(int index); SQLStatement* getMutableStatement(int index);
// Adds a statement to the result list of statements. // Get the list of all statements.
// Takes ownership of the statement. const std::vector<SQLStatement*>& getStatements() const;
void addStatement(SQLStatement* stmt);
// Set whether parsing was successful. // Returns a copy of the list of all statements in this result.
void setIsValid(bool isValid); // Removes them from this result.
std::vector<SQLStatement*> releaseStatements();
// Set the details of the error, if available.
// Takes ownership of errorMsg.
void setErrorDetails(char* errorMsg, int errorLine, int errorColumn);
// Deletes all statements and other data within the result.
void reset();
private: private:
// List of statements within the result. // List of statements within the result.
@ -70,4 +79,4 @@ namespace hsql {
} // namespace hsql } // namespace hsql
#endif // __SQLPARSERRESULT__ #endif // __SQLPARSER__SQLPARSER_RESULT_H__

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,7 @@
extern int hsql_debug; extern int hsql_debug;
#endif #endif
/* "%code requires" blocks. */ /* "%code requires" blocks. */
#line 41 "bison_parser.y" /* yacc.c:1909 */ #line 36 "bison_parser.y" /* yacc.c:1909 */
// %code requires block // %code requires block
@ -214,7 +214,7 @@ extern int hsql_debug;
union HSQL_STYPE union HSQL_STYPE
{ {
#line 100 "bison_parser.y" /* yacc.c:1909 */ #line 95 "bison_parser.y" /* yacc.c:1909 */
double fval; double fval;
int64_t ival; int64_t ival;
@ -242,7 +242,7 @@ union HSQL_STYPE
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::SQLParserResult* stmt_list; std::vector<hsql::SQLStatement*>* stmt_vec;
std::vector<char*>* str_vec; std::vector<char*>* str_vec;
std::vector<hsql::TableRef*>* table_vec; std::vector<hsql::TableRef*>* table_vec;
@ -275,6 +275,6 @@ struct HSQL_LTYPE
int hsql_parse (hsql::SQLParserResult** result, yyscan_t scanner); int hsql_parse (hsql::SQLParserResult* result, yyscan_t scanner);
#endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */ #endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */

View File

@ -18,14 +18,9 @@
using namespace hsql; using namespace hsql;
int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const char *msg) { int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const char *msg) {
delete *result; result->setIsValid(false);
result->setErrorDetails(strdup(msg), llocp->first_line, llocp->first_column);
SQLParserResult* list = new SQLParserResult();
list->setIsValid(false);
list->setErrorDetails(strdup(msg), llocp->first_line, llocp->first_column);
*result = list;
return 0; return 0;
} }
@ -90,7 +85,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
%lex-param { yyscan_t scanner } %lex-param { yyscan_t scanner }
// Define additional parameters for yyparse // Define additional parameters for yyparse
%parse-param { hsql::SQLParserResult** result } %parse-param { hsql::SQLParserResult* result }
%parse-param { yyscan_t scanner } %parse-param { yyscan_t scanner }
@ -124,7 +119,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::SQLParserResult* stmt_list; std::vector<hsql::SQLStatement*>* stmt_vec;
std::vector<char*>* str_vec; std::vector<char*>* str_vec;
std::vector<hsql::TableRef*>* table_vec; std::vector<hsql::TableRef*>* table_vec;
@ -147,7 +142,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
} }
} }
delete ($$); delete ($$);
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec> <order_vec> } <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec> <order_vec> <stmt_vec>
%destructor { delete ($$); } <*> %destructor { delete ($$); } <*>
@ -178,7 +173,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
/********************************* /*********************************
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html) ** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
*********************************/ *********************************/
%type <stmt_list> statement_list %type <stmt_vec> statement_list
%type <statement> statement preparable_statement %type <statement> statement preparable_statement
%type <exec_stmt> execute_statement %type <exec_stmt> execute_statement
%type <prep_stmt> prepare_statement %type <prep_stmt> prepare_statement
@ -243,14 +238,18 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
// Defines our general input. // Defines our general input.
input: input:
statement_list opt_semicolon { statement_list opt_semicolon {
*result = $1; for (SQLStatement* stmt : *$1) {
// Transfers ownership of the statement.
result->addStatement(stmt);
}
delete $1;
} }
; ;
statement_list: statement_list:
statement { $$ = new SQLParserResult($1); } statement { $$ = new std::vector<SQLStatement*>(); $$->push_back($1); }
| statement_list ';' statement { $1->addStatement($3); $$ = $1; } | statement_list ';' statement { $1->push_back($3); $$ = $1; }
; ;
statement: statement:
@ -288,7 +287,11 @@ prepare_statement:
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' { | PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
$$ = new PrepareStatement(); $$ = new PrepareStatement();
$$->name = $2; $$->name = $2;
$$->query = $4; $$->query = new SQLParserResult();
for (SQLStatement* stmt : *$4) {
$$->query->addStatement(stmt);
}
delete $4;
} }
; ;
@ -651,8 +654,8 @@ scalar_expr:
; ;
unary_expr: unary_expr:
'-' operand { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); } '-' operand { $$ = Expr::makeOpUnary(kOpMinus, $2); }
| NOT operand { $$ = Expr::makeOpUnary(Expr::NOT, $2); } | NOT operand { $$ = Expr::makeOpUnary(kOpNot, $2); }
; ;
binary_expr: binary_expr:
@ -663,20 +666,20 @@ binary_expr:
| operand '*' operand { $$ = Expr::makeOpBinary($1, '*', $3); } | operand '*' operand { $$ = Expr::makeOpBinary($1, '*', $3); }
| operand '%' operand { $$ = Expr::makeOpBinary($1, '%', $3); } | operand '%' operand { $$ = Expr::makeOpBinary($1, '%', $3); }
| operand '^' operand { $$ = Expr::makeOpBinary($1, '^', $3); } | operand '^' operand { $$ = Expr::makeOpBinary($1, '^', $3); }
| operand LIKE operand { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); } | operand LIKE operand { $$ = Expr::makeOpBinary($1, kOpLike, $3); }
| operand NOT LIKE operand { $$ = Expr::makeOpBinary($1, Expr::NOT_LIKE, $4); } | operand NOT LIKE operand { $$ = Expr::makeOpBinary($1, kOpNotLike, $4); }
; ;
logic_expr: logic_expr:
expr AND expr { $$ = Expr::makeOpBinary($1, Expr::AND, $3); } expr AND expr { $$ = Expr::makeOpBinary($1, kOpAnd, $3); }
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); } | expr OR expr { $$ = Expr::makeOpBinary($1, kOpOr, $3); }
; ;
in_expr: in_expr:
operand IN '(' expr_list ')' { $$ = Expr::makeInOperator($1, $4); } operand IN '(' expr_list ')' { $$ = Expr::makeInOperator($1, $4); }
| operand NOT IN '(' expr_list ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeInOperator($1, $5)); } | operand NOT IN '(' expr_list ')' { $$ = Expr::makeOpUnary(kOpNot, Expr::makeInOperator($1, $5)); }
| operand IN '(' select_no_paren ')' { $$ = Expr::makeInOperator($1, $4); } | operand IN '(' select_no_paren ')' { $$ = Expr::makeInOperator($1, $4); }
| operand NOT IN '(' select_no_paren ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeInOperator($1, $5)); } | operand NOT IN '(' select_no_paren ')' { $$ = Expr::makeOpUnary(kOpNot, Expr::makeInOperator($1, $5)); }
; ;
// TODO: allow no else specified // TODO: allow no else specified
@ -686,16 +689,16 @@ case_expr:
exists_expr: exists_expr:
EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); } EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); }
| NOT EXISTS '(' select_no_paren ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeExists($4)); } | NOT EXISTS '(' select_no_paren ')' { $$ = Expr::makeOpUnary(kOpNot, Expr::makeExists($4)); }
; ;
comp_expr: comp_expr:
operand '=' operand { $$ = Expr::makeOpBinary($1, '=', $3); } operand '=' operand { $$ = Expr::makeOpBinary($1, '=', $3); }
| operand NOTEQUALS operand { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); } | operand NOTEQUALS operand { $$ = Expr::makeOpBinary($1, kOpNotEquals, $3); }
| operand '<' operand { $$ = Expr::makeOpBinary($1, '<', $3); } | operand '<' operand { $$ = Expr::makeOpBinary($1, '<', $3); }
| operand '>' operand { $$ = Expr::makeOpBinary($1, '>', $3); } | operand '>' operand { $$ = Expr::makeOpBinary($1, '>', $3); }
| operand LESSEQ operand { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); } | operand LESSEQ operand { $$ = Expr::makeOpBinary($1, kOpLessEq, $3); }
| operand GREATEREQ operand { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); } | operand GREATEREQ operand { $$ = Expr::makeOpBinary($1, kOpGreaterEq, $3); }
; ;
function_expr: function_expr:

View File

@ -1,5 +1,5 @@
#ifndef __CREATE_STATEMENT_H__ #ifndef __SQLPARSER__CREATE_STATEMENT_H__
#define __CREATE_STATEMENT_H__ #define __SQLPARSER__CREATE_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -1,5 +1,5 @@
#ifndef __DELETE_STATEMENT_H__ #ifndef __SQLPARSER__DELETE_STATEMENT_H__
#define __DELETE_STATEMENT_H__ #define __SQLPARSER__DELETE_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -1,5 +1,5 @@
#ifndef __DROP_STATEMENT_H__ #ifndef __SQLPARSER__DROP_STATEMENT_H__
#define __DROP_STATEMENT_H__ #define __SQLPARSER__DROP_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -1,5 +1,5 @@
#ifndef __EXECUTE_STATEMENT_H__ #ifndef __SQLPARSER__EXECUTE_STATEMENT_H__
#define __EXECUTE_STATEMENT_H__ #define __SQLPARSER__EXECUTE_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -51,7 +51,7 @@ namespace hsql {
Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) { Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->opType = SIMPLE_OP; e->opType = kOpSimple;
e->opChar = op; e->opChar = op;
e->expr = expr1; e->expr = expr1;
e->expr2 = expr2; e->expr2 = expr2;
@ -61,7 +61,7 @@ namespace hsql {
Expr* Expr::makeBetween(Expr* expr, Expr* left, Expr* right) { Expr* Expr::makeBetween(Expr* expr, Expr* left, Expr* right) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->expr = expr; e->expr = expr;
e->opType = BETWEEN; e->opType = kOpBetween;
e->exprList = new std::vector<Expr*>(); e->exprList = new std::vector<Expr*>();
e->exprList->push_back(left); e->exprList->push_back(left);
e->exprList->push_back(right); e->exprList->push_back(right);
@ -71,7 +71,7 @@ namespace hsql {
Expr* Expr::makeCase(Expr* expr, Expr* then, Expr* other) { Expr* Expr::makeCase(Expr* expr, Expr* then, Expr* other) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->expr = expr; e->expr = expr;
e->opType = CASE; e->opType = kOpCase;
e->exprList = new std::vector<Expr*>(); e->exprList = new std::vector<Expr*>();
e->exprList->push_back(then); e->exprList->push_back(then);
e->exprList->push_back(other); e->exprList->push_back(other);
@ -132,14 +132,14 @@ namespace hsql {
Expr* Expr::makeExists(SelectStatement* select) { Expr* Expr::makeExists(SelectStatement* select) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->opType = EXISTS; e->opType = kOpExists;
e->select = select; e->select = select;
return e; return e;
} }
Expr* Expr::makeInOperator(Expr* expr, std::vector<Expr*>* exprList) { Expr* Expr::makeInOperator(Expr* expr, std::vector<Expr*>* exprList) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->opType = IN; e->opType = kOpIn;
e->expr = expr; e->expr = expr;
e->exprList = exprList; e->exprList = exprList;
@ -148,39 +148,39 @@ namespace hsql {
Expr* Expr::makeInOperator(Expr* expr, SelectStatement* select) { Expr* Expr::makeInOperator(Expr* expr, SelectStatement* select) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->opType = IN; e->opType = kOpIn;
e->expr = expr; e->expr = expr;
e->select = select; e->select = select;
return e; return e;
} }
bool Expr::isType(ExprType e_type) { bool Expr::isType(ExprType exprType) const {
return e_type == type; return exprType == type;
} }
bool Expr::isLiteral() { bool Expr::isLiteral() const {
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder); return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
} }
bool Expr::hasAlias() { bool Expr::hasAlias() const {
return alias != NULL; return alias != NULL;
} }
bool Expr::hasTable() { bool Expr::hasTable() const {
return table != NULL; return table != NULL;
} }
char* Expr::getName() { const char* Expr::getName() const {
if (alias != NULL) return alias; if (alias != NULL) return alias;
else return name; else return name;
} }
bool Expr::isSimpleOp() { bool Expr::isSimpleOp() const {
return opType == SIMPLE_OP; return opType == kOpSimple;
} }
bool Expr::isSimpleOp(char op) { bool Expr::isSimpleOp(char op) const {
return isSimpleOp() && opChar == op; return isSimpleOp() && opChar == op;
} }

View File

@ -1,5 +1,5 @@
#ifndef __EXPRESSION_H__ #ifndef __SQLPARSER__EXPR_H__
#define __EXPRESSION_H__ #define __SQLPARSER__EXPR_H__
#include <stdlib.h> #include <stdlib.h>
#include <memory> #include <memory>
@ -24,48 +24,45 @@ namespace hsql {
kExprSelect kExprSelect
}; };
// Operator types. These are important for expressions of type kExprOperator.
// Trivial types are those that can be described by a single character e.g:
// + - * / < > = %
// Non-trivial are: <> <= >= LIKE ISNULL NOT
enum OperatorType {
kOpNone,
// Ternary operators
kOpBetween,
kOpCase,
// Binary operators.
// Simple operators are identified by the opChar field (e.g. +, -, =, >, <).
kOpSimple,
kOpNotEquals,
kOpLessEq,
kOpGreaterEq,
kOpLike,
kOpNotLike,
kOpAnd,
kOpOr,
kOpIn,
// Unary operators.
kOpNot,
kOpMinus,
kOpIsNull,
kOpExists
};
typedef struct Expr Expr; typedef struct Expr Expr;
// Represents SQL expressions (i.e. literals, operators, column_refs). // Represents SQL expressions (i.e. literals, operators, column_refs).
// TODO: When destructing a placeholder expression, we might need to alter the placeholder_list. // TODO: When destructing a placeholder expression, we might need to alter the placeholder_list.
struct Expr { struct Expr {
// Operator types. These are important for expressions of type kExprOperator.
// Trivial types are those that can be described by a single character e.g:
// + - * / < > = %
// Non-trivial are: <> <= >= LIKE ISNULL NOT
enum OperatorType {
NONE,
// Ternary operators
BETWEEN,
CASE,
// Binary operators.
SIMPLE_OP,
NOT_EQUALS,
LESS_EQ,
GREATER_EQ,
LIKE,
NOT_LIKE,
AND,
OR,
IN,
// Unary operators.
NOT,
UMINUS,
ISNULL,
EXISTS
};
Expr(ExprType type); Expr(ExprType type);
virtual ~Expr();
// Interesting side-effect:
// Making the destructor virtual used to cause segmentation faults.
// TODO: inspect.
~Expr();
ExprType type; ExprType type;
@ -88,19 +85,19 @@ namespace hsql {
// Convenience accessor methods. // Convenience accessor methods.
bool isType(ExprType e_type); bool isType(ExprType exprType) const;
bool isLiteral(); bool isLiteral() const;
bool hasAlias(); bool hasAlias() const;
bool hasTable(); bool hasTable() const;
char* getName(); const char* getName() const;
bool isSimpleOp(); bool isSimpleOp() const;
bool isSimpleOp(char op); bool isSimpleOp(char op) const;
// Static constructors. // Static constructors.

View File

@ -1,5 +1,5 @@
#ifndef __IMPORT_STATEMENT_H__ #ifndef __SQLPARSER__IMPORT_STATEMENT_H__
#define __IMPORT_STATEMENT_H__ #define __SQLPARSER__IMPORT_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -1,5 +1,5 @@
#ifndef __INSERT_STATEMENT_H__ #ifndef __SQLPARSER__INSERT_STATEMENT_H__
#define __INSERT_STATEMENT_H__ #define __SQLPARSER__INSERT_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"
#include "SelectStatement.h" #include "SelectStatement.h"

View File

@ -1,5 +1,5 @@
#ifndef __PREPARE_STATEMENT_H__ #ifndef __SQLPARSER__PREPARE_STATEMENT_H__
#define __PREPARE_STATEMENT_H__ #define __SQLPARSER__PREPARE_STATEMENT_H__
#include "../SQLParserResult.h" #include "../SQLParserResult.h"
#include "SQLStatement.h" #include "SQLStatement.h"
@ -24,6 +24,8 @@ namespace hsql {
void setPlaceholders(std::vector<void*> ph); void setPlaceholders(std::vector<void*> ph);
char* name; char* name;
// The result that is stored within this prepared statement.
SQLParserResult* query; SQLParserResult* query;
// The expressions are not owned by this statement. // The expressions are not owned by this statement.

View File

@ -1,5 +1,5 @@
#ifndef __SQLSTATEMENT_H__ #ifndef __SQLPARSER__SQLSTATEMENT_H__
#define __SQLSTATEMENT_H__ #define __SQLPARSER__SQLSTATEMENT_H__
#include "Expr.h" #include "Expr.h"
#include <vector> #include <vector>
@ -29,11 +29,13 @@ namespace hsql {
virtual ~SQLStatement(); virtual ~SQLStatement();
virtual StatementType type() const; StatementType type() const;
bool isType(StatementType type) const;
private: private:
StatementType type_; StatementType type_;
}; };
} // namespace hsql } // namespace hsql
#endif // __SQLSTATEMENT_H__ #endif // __SQLPARSER__SQLSTATEMENT_H__

View File

@ -1,5 +1,5 @@
#ifndef __SELECT_STATEMENT_H__ #ifndef __SQLPARSER__SELECT_STATEMENT_H__
#define __SELECT_STATEMENT_H__ #define __SQLPARSER__SELECT_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"
#include "Expr.h" #include "Expr.h"
@ -13,7 +13,6 @@ namespace hsql {
/** /**
* Description of the order by clause within a select statement * Description of the order by clause within a select statement
* TODO: hold multiple expressions to be sorted by
*/ */
struct OrderDescription { struct OrderDescription {
OrderDescription(OrderType type, Expr* expr); OrderDescription(OrderType type, Expr* expr);
@ -41,8 +40,7 @@ namespace hsql {
*/ */
struct GroupByDescription { struct GroupByDescription {
GroupByDescription(); GroupByDescription();
// TODO: make virtual virtual ~GroupByDescription();
~GroupByDescription();
std::vector<Expr*>* columns; std::vector<Expr*>* columns;
Expr* having; Expr* having;

View File

@ -1,5 +1,5 @@
#ifndef __TABLEREF_H__ #ifndef __SQLPARSER__TABLEREF_H__
#define __TABLEREF_H__ #define __SQLPARSER__TABLEREF_H__
#include "Expr.h" #include "Expr.h"
#include <stdio.h> #include <stdio.h>
@ -35,10 +35,10 @@ namespace hsql {
JoinDefinition* join; JoinDefinition* join;
// Returns true if a schema is set. // Returns true if a schema is set.
bool hasSchema(); bool hasSchema() const;
// Returns the alias, if it is set. Otherwise the name. // Returns the alias, if it is set. Otherwise the name.
char* getName(); const char* getName() const;
}; };
// Possible types of joins. // Possible types of joins.

View File

@ -1,5 +1,5 @@
#ifndef __UPDATE_STATEMENT_H__ #ifndef __SQLPARSER__UPDATE_STATEMENT_H__
#define __UPDATE_STATEMENT_H__ #define __SQLPARSER__UPDATE_STATEMENT_H__
#include "SQLStatement.h" #include "SQLStatement.h"

View File

@ -13,6 +13,10 @@ namespace hsql {
return type_; return type_;
} }
bool SQLStatement::isType(StatementType type) const {
return (type_ == type);
}
// ColumnDefinition // ColumnDefinition
ColumnDefinition::ColumnDefinition(char* name, DataType type) : ColumnDefinition::ColumnDefinition(char* name, DataType type) :
name(name), name(name),
@ -268,11 +272,11 @@ namespace hsql {
} }
} }
bool TableRef::hasSchema() { bool TableRef::hasSchema() const {
return schema != NULL; return schema != NULL;
} }
char* TableRef::getName() { const char* TableRef::getName() const {
if (alias != NULL) return alias; if (alias != NULL) return alias;
else return name; else return name;
} }

View File

@ -1,5 +1,5 @@
#ifndef __STATEMENTS_H__ #ifndef __SQLPARSER__STATEMENTS_H__
#define __STATEMENTS_H__ #define __SQLPARSER__STATEMENTS_H__
#include "SelectStatement.h" #include "SelectStatement.h"
#include "ImportStatement.h" #include "ImportStatement.h"
@ -11,4 +11,4 @@
#include "PrepareStatement.h" #include "PrepareStatement.h"
#include "ExecuteStatement.h" #include "ExecuteStatement.h"
#endif // __STATEMENTS_H__ #endif // __SQLPARSER__STATEMENTS_H__

View File

@ -63,16 +63,16 @@ namespace hsql {
} }
switch (expr->opType) { switch (expr->opType) {
case Expr::SIMPLE_OP: case kOpSimple:
inprintC(expr->opChar, numIndent); inprintC(expr->opChar, numIndent);
break; break;
case Expr::AND: case kOpAnd:
inprint("AND", numIndent); inprint("AND", numIndent);
break; break;
case Expr::OR: case kOpOr:
inprint("OR", numIndent); inprint("OR", numIndent);
break; break;
case Expr::NOT: case kOpNot:
inprint("NOT", numIndent); inprint("NOT", numIndent);
break; break;
default: default:

View File

@ -1,7 +1,7 @@
#ifndef __SQLHELPER_H__ #ifndef __SQLPARSER__SQLHELPER_H__
#define __SQLHELPER_H__ #define __SQLPARSER__SQLHELPER_H__
#include "sql/statements.h" #include "../sql/statements.h"
namespace hsql { namespace hsql {

82
test/prepare_tests.cpp Normal file
View File

@ -0,0 +1,82 @@
#include "thirdparty/microtest/microtest.h"
#include "sql_asserts.h"
#include "SQLParser.h"
using hsql::kExprPlaceholder;
using hsql::kStmtDrop;
using hsql::kStmtExecute;
using hsql::kStmtInsert;
using hsql::kStmtPrepare;
using hsql::kStmtSelect;
using hsql::DropStatement;
using hsql::ExecuteStatement;
using hsql::InsertStatement;
using hsql::PrepareStatement;
using hsql::SelectStatement;
TEST(PrepareSingleStatementTest) {
const std::string query = "PREPARE test: SELECT * FROM students WHERE grade = ?;";
TEST_PARSE_SINGLE_SQL(query, kStmtPrepare, PrepareStatement, result, prepare);
const SelectStatement* select = (const SelectStatement*) prepare->query->getStatement(0);
ASSERT(select->whereClause->isSimpleOp('='));
ASSERT_EQ(select->whereClause->expr2, prepare->placeholders[0])
}
TEST(PrepareMultiStatementTest) {
const std::string query = "PREPARE test {"
"INSERT INTO test VALUES(?);"
"SELECT ?, test FROM test WHERE c1 = ?;"
"};"
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
"DEALLOCATE PREPARE stmt;";
TEST_PARSE_SQL_QUERY(query, result, 3);
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
// Prepare Statement #1
ASSERT_STREQ(prep1->name, "test");
ASSERT_EQ(prep1->placeholders.size(), 3);
ASSERT_EQ(prep1->query->size(), 2);
TEST_CAST_STMT((*prep1->query), 0, kStmtInsert, InsertStatement, insert);
TEST_CAST_STMT((*prep1->query), 1, kStmtSelect, SelectStatement, select);
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
// Check IDs of placeholders
ASSERT_EQ(insert->values->at(0)->ival, 0);
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
ASSERT_EQ(select->selectList->at(0)->ival, 1);
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
ASSERT_EQ(select->whereClause->expr2->ival, 2);
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
// Prepare Statement #2
ASSERT_STREQ(prep2->name, "stmt");
ASSERT_EQ(prep2->placeholders.size(), 1);
// Deallocate Statement
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
ASSERT_STREQ(drop->name, "stmt");
}
TEST(ExecuteStatementTest) {
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
ASSERT_STREQ(stmt->name, "test");
ASSERT_EQ(stmt->parameters->size(), 2);
}

View File

@ -16,8 +16,6 @@ TEST(SelectTest) {
ASSERT_NULL(stmt->whereClause); ASSERT_NULL(stmt->whereClause);
ASSERT_NULL(stmt->groupBy); ASSERT_NULL(stmt->groupBy);
delete result;
} }
TEST(SelectExprTest) { TEST(SelectExprTest) {
@ -55,8 +53,6 @@ TEST(SelectExprTest) {
ASSERT_EQ(stmt->selectList->at(2)->exprList->at(1)->exprList->size(), 1); ASSERT_EQ(stmt->selectList->at(2)->exprList->at(1)->exprList->size(), 1);
ASSERT(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->isType(kExprColumnRef)); ASSERT(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->isType(kExprColumnRef));
ASSERT_STREQ(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->getName(), "un"); ASSERT_STREQ(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->getName(), "un");
delete result;
} }
@ -76,8 +72,6 @@ TEST(SelectHavingTest) {
ASSERT(group->having->isSimpleOp('<')); ASSERT(group->having->isSimpleOp('<'));
ASSERT(group->having->expr->isType(kExprFunctionRef)); ASSERT(group->having->expr->isType(kExprFunctionRef));
ASSERT(group->having->expr2->isType(kExprLiteralFloat)); ASSERT(group->having->expr2->isType(kExprLiteralFloat));
delete result;
} }
@ -91,8 +85,6 @@ TEST(SelectDistinctTest) {
ASSERT(stmt->selectDistinct); ASSERT(stmt->selectDistinct);
ASSERT_NULL(stmt->whereClause); ASSERT_NULL(stmt->whereClause);
delete result;
} }
TEST(SelectGroupDistinctTest) { TEST(SelectGroupDistinctTest) {
@ -107,8 +99,6 @@ TEST(SelectGroupDistinctTest) {
ASSERT_EQ(stmt->selectList->size(), 3); ASSERT_EQ(stmt->selectList->size(), 3);
ASSERT(!stmt->selectList->at(1)->distinct); ASSERT(!stmt->selectList->at(1)->distinct);
ASSERT(stmt->selectList->at(2)->distinct); ASSERT(stmt->selectList->at(2)->distinct);
delete result;
} }
TEST(OrderByTest) { TEST(OrderByTest) {
@ -128,8 +118,6 @@ TEST(OrderByTest) {
ASSERT_EQ(stmt->order->at(1)->type, kOrderDesc); ASSERT_EQ(stmt->order->at(1)->type, kOrderDesc);
ASSERT_STREQ(stmt->order->at(1)->expr->name, "city"); ASSERT_STREQ(stmt->order->at(1)->expr->name, "city");
delete result;
} }
TEST(SelectBetweenTest) { TEST(SelectBetweenTest) {
@ -144,7 +132,7 @@ TEST(SelectBetweenTest) {
Expr* where = stmt->whereClause; Expr* where = stmt->whereClause;
ASSERT_NOTNULL(where); ASSERT_NOTNULL(where);
ASSERT(where->isType(kExprOperator)); ASSERT(where->isType(kExprOperator));
ASSERT_EQ(where->opType, Expr::BETWEEN); ASSERT_EQ(where->opType, kOpBetween);
ASSERT_STREQ(where->expr->getName(), "grade"); ASSERT_STREQ(where->expr->getName(), "grade");
ASSERT(where->expr->isType(kExprColumnRef)); ASSERT(where->expr->isType(kExprColumnRef));
@ -154,8 +142,6 @@ TEST(SelectBetweenTest) {
ASSERT_EQ(where->exprList->at(0)->ival, 1); ASSERT_EQ(where->exprList->at(0)->ival, 1);
ASSERT(where->exprList->at(1)->isType(kExprColumnRef)); ASSERT(where->exprList->at(1)->isType(kExprColumnRef));
ASSERT_STREQ(where->exprList->at(1)->getName(), "c"); ASSERT_STREQ(where->exprList->at(1)->getName(), "c");
delete result;
} }
TEST(SelectConditionalSelectTest) { TEST(SelectConditionalSelectTest) {
@ -169,7 +155,7 @@ TEST(SelectConditionalSelectTest) {
Expr* where = stmt->whereClause; Expr* where = stmt->whereClause;
ASSERT_NOTNULL(where); ASSERT_NOTNULL(where);
ASSERT(where->isType(kExprOperator)); ASSERT(where->isType(kExprOperator));
ASSERT_EQ(where->opType, Expr::AND); ASSERT_EQ(where->opType, kOpAnd);
// a = (SELECT ...) // a = (SELECT ...)
Expr* cond1 = where->expr; Expr* cond1 = where->expr;
@ -189,13 +175,11 @@ TEST(SelectConditionalSelectTest) {
// EXISTS (SELECT ...) // EXISTS (SELECT ...)
Expr* cond2 = where->expr2; Expr* cond2 = where->expr2;
ASSERT_EQ(cond2->opType, Expr::EXISTS); ASSERT_EQ(cond2->opType, kOpExists);
ASSERT_NOTNULL(cond2->select); ASSERT_NOTNULL(cond2->select);
SelectStatement* ex_select = cond2->select; SelectStatement* ex_select = cond2->select;
ASSERT_STREQ(ex_select->fromTable->getName(), "test"); ASSERT_STREQ(ex_select->fromTable->getName(), "test");
delete result;
} }
TEST(SelectCaseWhen) { TEST(SelectCaseWhen) {
@ -216,10 +200,8 @@ TEST(SelectCaseWhen) {
Expr* caseExpr = func->exprList->at(0); Expr* caseExpr = func->exprList->at(0);
ASSERT_NOTNULL(caseExpr); ASSERT_NOTNULL(caseExpr);
ASSERT(caseExpr->isType(kExprOperator)); ASSERT(caseExpr->isType(kExprOperator));
ASSERT_EQ(caseExpr->opType, Expr::CASE); ASSERT_EQ(caseExpr->opType, kOpCase);
ASSERT(caseExpr->expr->isType(kExprOperator)); ASSERT(caseExpr->expr->isType(kExprOperator));
ASSERT(caseExpr->expr->isSimpleOp('=')); ASSERT(caseExpr->expr->isSimpleOp('='));
ASSERT_EQ(caseExpr->exprList->size(), 2); ASSERT_EQ(caseExpr->exprList->size(), 2);
delete result;
} }

View File

@ -3,20 +3,21 @@
#define TEST_PARSE_SQL_QUERY(query, result, numStatements) \ #define TEST_PARSE_SQL_QUERY(query, result, numStatements) \
const SQLParserResult* result = SQLParser::parseSQLString(query); \ hsql::SQLParserResult result; \
ASSERT(result->isValid()); \ hsql::SQLParser::parseSQLString(query, &result); \
ASSERT_EQ(result->size(), numStatements); ASSERT(result.isValid()); \
ASSERT_EQ(result.size(), numStatements);
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \ #define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \
TEST_PARSE_SQL_QUERY(query, result, 1); \ TEST_PARSE_SQL_QUERY(query, result, 1); \
ASSERT_EQ(result->getStatement(0)->type(), stmtType); \ ASSERT_EQ(result.getStatement(0)->type(), stmtType); \
const stmtClass* outputVar = (const stmtClass*) result->getStatement(0); const stmtClass* outputVar = (const stmtClass*) result.getStatement(0);
#define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \ #define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \
ASSERT_EQ(result->getStatement(stmt_index)->type(), stmtType); \ ASSERT_EQ(result.getStatement(stmt_index)->type(), stmtType); \
const stmtClass* outputVar = (const stmtClass*) result->getStatement(stmt_index); const stmtClass* outputVar = (const stmtClass*) result.getStatement(stmt_index);
#endif #endif

View File

@ -79,23 +79,22 @@ TEST(AutoGrammarTest) {
start = std::chrono::system_clock::now(); start = std::chrono::system_clock::now();
// Parsing // Parsing
SQLParserResult* result = SQLParser::parseSQLString(sql.c_str()); SQLParserResult result;
SQLParser::parseSQLString(sql.c_str(), &result);
end = std::chrono::system_clock::now(); end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start; std::chrono::duration<double> elapsed_seconds = end - start;
double us = elapsed_seconds.count() * 1000 * 1000; double us = elapsed_seconds.count() * 1000 * 1000;
if (expectFalse == result->isValid()) { if (expectFalse == result.isValid()) {
printf("\033[0;31m{ failed}\033[0m\n"); printf("\033[0;31m{ failed}\033[0m\n");
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result->errorMsg(), result->errorLine(), result->errorColumn()); printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result.errorMsg(), result.errorLine(), result.errorColumn());
printf("\t%s\n", sql.c_str()); printf("\t%s\n", sql.c_str());
numFailed++; numFailed++;
} else { } else {
// TODO: indicate whether expectFalse was set // TODO: indicate whether expectFalse was set
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str()); printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
} }
delete result;
} }
if (numFailed == 0) { if (numFailed == 0) {

View File

@ -3,36 +3,40 @@
*/ */
#include "thirdparty/microtest/microtest.h" #include "thirdparty/microtest/microtest.h"
#include "sql_asserts.h"
#include "SQLParser.h" #include "SQLParser.h"
#include "sqlhelper.h" #include "util/sqlhelper.h"
#include "sql_asserts.h"
using namespace hsql; using namespace hsql;
TEST(DeleteStatementTest) { TEST(DeleteStatementTest) {
const SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); SQLParserResult result;
ASSERT(result->isValid()); SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;", &result);
ASSERT_EQ(result->size(), 1);
ASSERT(result->getStatement(0)->type() == kStmtDelete);
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0); ASSERT(result.isValid());
ASSERT_EQ(result.size(), 1);
ASSERT(result.getStatement(0)->type() == kStmtDelete);
const DeleteStatement* stmt = (const DeleteStatement*) result.getStatement(0);
ASSERT_STREQ(stmt->tableName, "students"); ASSERT_STREQ(stmt->tableName, "students");
ASSERT_NOTNULL(stmt->expr); ASSERT_NOTNULL(stmt->expr);
ASSERT(stmt->expr->isType(kExprOperator)); ASSERT(stmt->expr->isType(kExprOperator));
ASSERT_STREQ(stmt->expr->expr->name, "grade"); ASSERT_STREQ(stmt->expr->expr->name, "grade");
ASSERT_EQ(stmt->expr->expr2->fval, 2.0); ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
delete result;
} }
TEST(CreateStatementTest) { TEST(CreateStatementTest) {
const SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)"); SQLParserResult result;
ASSERT(result->isValid()); SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)", &result);
ASSERT_EQ(result->size(), 1);
ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0); ASSERT(result.isValid());
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.getStatement(0)->type(), kStmtCreate);
const CreateStatement* stmt = (const CreateStatement*) result.getStatement(0);
ASSERT_EQ(stmt->type, CreateStatement::kTable); ASSERT_EQ(stmt->type, CreateStatement::kTable);
ASSERT_STREQ(stmt->tableName, "students"); ASSERT_STREQ(stmt->tableName, "students");
ASSERT_NOTNULL(stmt->columns); ASSERT_NOTNULL(stmt->columns);
@ -45,18 +49,18 @@ TEST(CreateStatementTest) {
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT); ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT); ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE); ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
delete result;
} }
TEST(UpdateStatementTest) { TEST(UpdateStatementTest) {
const SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';"); SQLParserResult result;
ASSERT(result->isValid()); SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';", &result);
ASSERT_EQ(result->size(), 1);
ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0); ASSERT(result.isValid());
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.getStatement(0)->type(), kStmtUpdate);
const UpdateStatement* stmt = (const UpdateStatement*) result.getStatement(0);
ASSERT_NOTNULL(stmt->table); ASSERT_NOTNULL(stmt->table);
ASSERT_STREQ(stmt->table->name, "students"); ASSERT_STREQ(stmt->table->name, "students");
@ -74,9 +78,6 @@ TEST(UpdateStatementTest) {
ASSERT(stmt->where->isSimpleOp('=')); ASSERT(stmt->where->isSimpleOp('='));
ASSERT_STREQ(stmt->where->expr->name, "name"); ASSERT_STREQ(stmt->where->expr->name, "name");
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann"); ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");
\
delete result;
} }
@ -90,8 +91,6 @@ TEST(InsertStatementTest) {
ASSERT_EQ(stmt->values->size(), 4); ASSERT_EQ(stmt->values->size(), 4);
// TODO // TODO
delete result;
} }
@ -106,66 +105,26 @@ TEST(DropTableStatementTest) {
ASSERT_EQ(stmt->type, DropStatement::kTable); ASSERT_EQ(stmt->type, DropStatement::kTable);
ASSERT_NOTNULL(stmt->name); ASSERT_NOTNULL(stmt->name);
ASSERT_STREQ(stmt->name, "students"); ASSERT_STREQ(stmt->name, "students");
delete result;
} }
TEST(ReleaseStatementTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students;",
kStmtSelect,
SelectStatement,
result,
stmt);
TEST(PrepareStatementTest) { ASSERT_EQ(1, result.size());
std::string query = "PREPARE test {" ASSERT_NULL(stmt->whereClause);
"INSERT INTO test VALUES(?);"
"SELECT ?, test FROM test WHERE c1 = ?;"
"};"
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
"DEALLOCATE PREPARE stmt;";
TEST_PARSE_SQL_QUERY(query, result, 3); std::vector<SQLStatement*> statements = result.releaseStatements();
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1); ASSERT_EQ(0, result.size());
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
// Prepare Statement #1 for (SQLStatement* stmt : statements) {
ASSERT_STREQ(prep1->name, "test"); delete stmt;
ASSERT_EQ(prep1->placeholders.size(), 3); }
ASSERT_EQ(prep1->query->size(), 2);
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
// Check IDs of placeholders
ASSERT_EQ(insert->values->at(0)->ival, 0);
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
ASSERT_EQ(select->selectList->at(0)->ival, 1);
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
ASSERT_EQ(select->whereClause->expr2->ival, 2);
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
// Prepare Statement #2
ASSERT_STREQ(prep2->name, "stmt");
ASSERT_EQ(prep2->placeholders.size(), 1);
// Deallocate Statement
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
ASSERT_STREQ(drop->name, "stmt");
delete result;
}
TEST(ExecuteStatementTest) {
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
ASSERT_STREQ(stmt->name, "test");
ASSERT_EQ(stmt->parameters->size(), 2);
delete result;
} }
TEST_MAIN(); TEST_MAIN();

View File

@ -1,7 +1,9 @@
#include "thirdparty/microtest/microtest.h" #include "thirdparty/microtest/microtest.h"
#include "sql_asserts.h"
#include "SQLParser.h" #include "SQLParser.h"
#include "sqlhelper.h" #include "util/sqlhelper.h"
#include "sql_asserts.h"
#include <string> #include <string>
#include <fstream> #include <fstream>
@ -37,15 +39,15 @@ TEST(TPCHQueryGrammarTests) {
for (const std::string& file_path : files) { for (const std::string& file_path : files) {
std::string query = readFileContents(file_path); std::string query = readFileContents(file_path);
SQLParserResult* result = SQLParser::parseSQLString(query.c_str()); SQLParserResult result;
if (!result->isValid()) { SQLParser::parseSQLString(query.c_str(), &result);
if (!result.isValid()) {
mt::printFailed(file_path.c_str()); mt::printFailed(file_path.c_str());
printf("%s %s (L%d:%d)%s\n", mt::red(), result->errorMsg(), result->errorLine(), result->errorColumn(), mt::def()); printf("%s %s (L%d:%d)%s\n", mt::red(), result.errorMsg(), result.errorLine(), result.errorColumn(), mt::def());
++testsFailed; ++testsFailed;
} else { } else {
mt::printOk(file_path.c_str()); mt::printOk(file_path.c_str());
} }
delete result;
} }
ASSERT_EQ(testsFailed, 0); ASSERT_EQ(testsFailed, 0);
} }
@ -53,11 +55,12 @@ TEST(TPCHQueryGrammarTests) {
TEST(TPCHQueryDetailTest) { TEST(TPCHQueryDetailTest) {
std::string query = readFileContents("test/queries/tpc-h-16-22.sql"); std::string query = readFileContents("test/queries/tpc-h-16-22.sql");
SQLParserResult* result = SQLParser::parseSQLString(query.c_str()); SQLParserResult result;
ASSERT(result->isValid()); SQLParser::parseSQLString(query.c_str(), &result);
ASSERT_EQ(result->size(), 7); ASSERT(result.isValid());
ASSERT_EQ(result.size(), 7);
const SQLStatement* stmt20 = result->getStatement(4); const SQLStatement* stmt20 = result.getStatement(4);
ASSERT_EQ(stmt20->type(), kStmtSelect); ASSERT_EQ(stmt20->type(), kStmtSelect);
const SelectStatement* select20 = (const SelectStatement*) stmt20; const SelectStatement* select20 = (const SelectStatement*) stmt20;
@ -69,18 +72,18 @@ TEST(TPCHQueryDetailTest) {
Expr* where = select20->whereClause; Expr* where = select20->whereClause;
ASSERT_NOTNULL(where); ASSERT_NOTNULL(where);
ASSERT(where->isType(kExprOperator)); ASSERT(where->isType(kExprOperator));
ASSERT_EQ(where->opType, Expr::AND); ASSERT_EQ(where->opType, kOpAnd);
Expr* andExpr2 = where->expr; Expr* andExpr2 = where->expr;
ASSERT_NOTNULL(andExpr2); ASSERT_NOTNULL(andExpr2);
ASSERT(andExpr2->isType(kExprOperator)); ASSERT(andExpr2->isType(kExprOperator));
ASSERT_EQ(andExpr2->opType, Expr::AND); ASSERT_EQ(andExpr2->opType, kOpAnd);
// Test IN expression. // Test IN expression.
Expr* inExpr = andExpr2->expr; Expr* inExpr = andExpr2->expr;
ASSERT_NOTNULL(inExpr); ASSERT_NOTNULL(inExpr);
ASSERT(inExpr->isType(kExprOperator)); ASSERT(inExpr->isType(kExprOperator));
ASSERT_EQ(inExpr->opType, Expr::IN); ASSERT_EQ(inExpr->opType, kOpIn);
ASSERT_STREQ(inExpr->expr->getName(), "S_SUPPKEY"); ASSERT_STREQ(inExpr->expr->getName(), "S_SUPPKEY");
ASSERT_NOTNULL(inExpr->select); ASSERT_NOTNULL(inExpr->select);
@ -93,6 +96,4 @@ TEST(TPCHQueryDetailTest) {
ASSERT_EQ(select20->order->size(), 1); ASSERT_EQ(select20->order->size(), 1);
ASSERT(select20->order->at(0)->expr->isType(kExprColumnRef)); ASSERT(select20->order->at(0)->expr->isType(kExprColumnRef));
ASSERT_STREQ(select20->order->at(0)->expr->getName(), "S_NAME"); ASSERT_STREQ(select20->order->at(0)->expr->getName(), "S_NAME");
delete result;
} }