commit
9184d5d0c2
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
@ -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
|
@ -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 */
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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__
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__
|
|
@ -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:
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
|
@ -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;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue