commit
2bce9cc154
15
.travis.yml
15
.travis.yml
|
@ -4,17 +4,30 @@ language: cpp
|
||||||
install:
|
install:
|
||||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
- sudo apt-get -qq update
|
- sudo apt-get -qq update
|
||||||
- sudo apt-get install -y bison flex
|
|
||||||
- sudo apt-get install -y g++-4.8 libstdc++-4.8-dev
|
- sudo apt-get install -y g++-4.8 libstdc++-4.8-dev
|
||||||
|
- sudo apt-get install -y flex valgrind
|
||||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
|
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
|
||||||
|
|
||||||
|
# Install bison 3.0.4.
|
||||||
|
- wget http://ftp.gnu.org/gnu/bison/bison-3.0.4.tar.gz
|
||||||
|
- tar -xvzf bison-3.0.4.tar.gz
|
||||||
|
- cd bison-3.0.4
|
||||||
|
- ./configure && make && sudo make install
|
||||||
|
- cd ..
|
||||||
|
|
||||||
|
# Show installed versions.
|
||||||
- which g++
|
- which g++
|
||||||
- g++ -v
|
- g++ -v
|
||||||
|
- bison --version
|
||||||
|
- flex --version
|
||||||
|
- valgrind --version
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- make cleanall
|
||||||
- make
|
- make
|
||||||
- make test
|
- make test
|
||||||
|
|
|
@ -28,11 +28,12 @@ namespace hsql {
|
||||||
// Parser and return early if it failed.
|
// Parser and return early if it failed.
|
||||||
if (hsql_parse(&result, scanner)) {
|
if (hsql_parse(&result, scanner)) {
|
||||||
// Returns an error stmt object.
|
// Returns an error stmt object.
|
||||||
|
hsql__delete_buffer(state, scanner);
|
||||||
|
hsql_lex_destroy(scanner);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
hsql__delete_buffer(state, scanner);
|
hsql__delete_buffer(state, scanner);
|
||||||
|
|
||||||
hsql_lex_destroy(scanner);
|
hsql_lex_destroy(scanner);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace hsql {
|
||||||
delete statement;
|
delete statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete errorMsg_;
|
free(errorMsg_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SQLParserResult::addStatement(SQLStatement* stmt) {
|
void SQLParserResult::addStatement(SQLStatement* stmt) {
|
||||||
|
@ -57,7 +57,7 @@ namespace hsql {
|
||||||
isValid_ = isValid;
|
isValid_ = isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SQLParserResult::setErrorDetails(const char* errorMsg, int errorLine, int errorColumn) {
|
void SQLParserResult::setErrorDetails(char* errorMsg, int errorLine, int errorColumn) {
|
||||||
errorMsg_ = errorMsg;
|
errorMsg_ = errorMsg;
|
||||||
errorLine_ = errorLine;
|
errorLine_ = errorLine;
|
||||||
errorColumn_ = errorColumn;
|
errorColumn_ = errorColumn;
|
||||||
|
|
|
@ -47,7 +47,8 @@ namespace hsql {
|
||||||
void setIsValid(bool isValid);
|
void setIsValid(bool isValid);
|
||||||
|
|
||||||
// Set the details of the error, if available.
|
// Set the details of the error, if available.
|
||||||
void setErrorDetails(const char* errorMsg, int errorLine, int errorColumn);
|
// Takes ownership of errorMsg.
|
||||||
|
void setErrorDetails(char* errorMsg, int errorLine, int errorColumn);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -58,7 +59,7 @@ namespace hsql {
|
||||||
bool isValid_;
|
bool isValid_;
|
||||||
|
|
||||||
// Error message, if an error occurred.
|
// Error message, if an error occurred.
|
||||||
const char* errorMsg_;
|
char* errorMsg_;
|
||||||
|
|
||||||
// Line number of the occurrance of the error in the query.
|
// Line number of the occurrance of the error in the query.
|
||||||
int errorLine_;
|
int errorLine_;
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
all: bison_parser.cpp flex_lexer.cpp
|
all: bison_parser.cpp flex_lexer.cpp
|
||||||
|
|
||||||
bison_parser.cpp: bison_parser.y
|
bison_parser.cpp: bison_parser.y
|
||||||
|
@bison --version | head -n 1
|
||||||
bison bison_parser.y -v
|
bison bison_parser.y -v
|
||||||
|
|
||||||
flex_lexer.cpp: flex_lexer.l
|
flex_lexer.cpp: flex_lexer.l
|
||||||
|
@flex --version
|
||||||
flex flex_lexer.l
|
flex flex_lexer.l
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
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 40 "bison_parser.y" /* yacc.c:1909 */
|
#line 41 "bison_parser.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
// %code requires block
|
// %code requires block
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ extern int hsql_debug;
|
||||||
typedef union HSQL_STYPE HSQL_STYPE;
|
typedef union HSQL_STYPE HSQL_STYPE;
|
||||||
union HSQL_STYPE
|
union HSQL_STYPE
|
||||||
{
|
{
|
||||||
#line 99 "bison_parser.y" /* yacc.c:1909 */
|
#line 100 "bison_parser.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
double fval;
|
double fval;
|
||||||
int64_t ival;
|
int64_t ival;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
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;
|
||||||
|
|
||||||
SQLParserResult* list = new SQLParserResult();
|
SQLParserResult* list = new SQLParserResult();
|
||||||
list->setIsValid(false);
|
list->setIsValid(false);
|
||||||
|
@ -133,6 +134,19 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
** Descrutor symbols
|
||||||
|
*********************************/
|
||||||
|
%destructor { } <fval> <ival> <uval> <bval> <order_type>
|
||||||
|
%destructor { free( ($$) ); } <sval>
|
||||||
|
%destructor {
|
||||||
|
for (auto ptr : *($$)) {
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
delete ($$);
|
||||||
|
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec>
|
||||||
|
%destructor { delete ($$); } <*>
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Token Definition
|
** Token Definition
|
||||||
|
@ -303,7 +317,7 @@ import_file_type:
|
||||||
;
|
;
|
||||||
|
|
||||||
file_path:
|
file_path:
|
||||||
string_literal { $$ = $1->name; }
|
string_literal { $$ = strdup($1->name); delete $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,8 @@ namespace hsql {
|
||||||
|
|
||||||
CreateType type;
|
CreateType type;
|
||||||
bool ifNotExists; // default: false
|
bool ifNotExists; // default: false
|
||||||
const char* filePath; // default: NULL
|
char* filePath; // default: NULL
|
||||||
const char* tableName; // default: NULL
|
char* tableName; // default: NULL
|
||||||
std::vector<ColumnDefinition*>* columns; // default: NULL
|
std::vector<ColumnDefinition*>* columns; // default: NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace hsql {
|
||||||
virtual ~DropStatement();
|
virtual ~DropStatement();
|
||||||
|
|
||||||
EntityType type;
|
EntityType type;
|
||||||
const char* name;
|
char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace hsql {
|
||||||
ExecuteStatement();
|
ExecuteStatement();
|
||||||
virtual ~ExecuteStatement();
|
virtual ~ExecuteStatement();
|
||||||
|
|
||||||
const char* name;
|
char* name;
|
||||||
std::vector<Expr*>* parameters;
|
std::vector<Expr*>* parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,9 @@ namespace hsql {
|
||||||
Expr::~Expr() {
|
Expr::~Expr() {
|
||||||
delete expr;
|
delete expr;
|
||||||
delete expr2;
|
delete expr2;
|
||||||
delete name;
|
free(name);
|
||||||
delete table;
|
free(table);
|
||||||
|
free(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||||
|
@ -123,7 +124,7 @@ namespace hsql {
|
||||||
|
|
||||||
char* substr(const char* source, int from, int to) {
|
char* substr(const char* source, int from, int to) {
|
||||||
int len = to - from;
|
int len = to - from;
|
||||||
char* copy = new char[len + 1];
|
char* copy = (char*) malloc(len + 1);;
|
||||||
strncpy(copy, source + from, len);
|
strncpy(copy, source + from, len);
|
||||||
copy[len] = '\0';
|
copy[len] = '\0';
|
||||||
return copy;
|
return copy;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace hsql {
|
||||||
virtual ~InsertStatement();
|
virtual ~InsertStatement();
|
||||||
|
|
||||||
InsertType type;
|
InsertType type;
|
||||||
const char* tableName;
|
char* tableName;
|
||||||
std::vector<char*>* columns;
|
std::vector<char*>* columns;
|
||||||
std::vector<Expr*>* values;
|
std::vector<Expr*>* values;
|
||||||
SelectStatement* select;
|
SelectStatement* select;
|
||||||
|
|
|
@ -23,8 +23,12 @@ namespace hsql {
|
||||||
*/
|
*/
|
||||||
void setPlaceholders(std::vector<void*> ph);
|
void setPlaceholders(std::vector<void*> ph);
|
||||||
|
|
||||||
const char* name;
|
char* name;
|
||||||
SQLParserResult* query;
|
SQLParserResult* query;
|
||||||
|
|
||||||
|
// The expressions are not owned by this statement.
|
||||||
|
// Rather they are owned by the query and destroyed, when
|
||||||
|
// the query is destroyed.
|
||||||
std::vector<Expr*> placeholders;
|
std::vector<Expr*> placeholders;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace hsql {
|
||||||
type(type) {};
|
type(type) {};
|
||||||
|
|
||||||
ColumnDefinition::~ColumnDefinition() {
|
ColumnDefinition::~ColumnDefinition() {
|
||||||
delete name;
|
free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateStatemnet
|
// CreateStatemnet
|
||||||
|
@ -32,9 +32,15 @@ namespace hsql {
|
||||||
columns(NULL) {};
|
columns(NULL) {};
|
||||||
|
|
||||||
CreateStatement::~CreateStatement() {
|
CreateStatement::~CreateStatement() {
|
||||||
delete columns;
|
free(filePath);
|
||||||
delete filePath;
|
free(tableName);
|
||||||
delete tableName;
|
|
||||||
|
if (columns != NULL) {
|
||||||
|
for (ColumnDefinition* def : *columns) {
|
||||||
|
delete def;
|
||||||
|
}
|
||||||
|
delete columns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteStatement
|
// DeleteStatement
|
||||||
|
@ -44,7 +50,7 @@ namespace hsql {
|
||||||
expr(NULL) {};
|
expr(NULL) {};
|
||||||
|
|
||||||
DeleteStatement::~DeleteStatement() {
|
DeleteStatement::~DeleteStatement() {
|
||||||
delete tableName;
|
free(tableName);
|
||||||
delete expr;
|
delete expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +61,7 @@ namespace hsql {
|
||||||
name(NULL) {}
|
name(NULL) {}
|
||||||
|
|
||||||
DropStatement::~DropStatement() {
|
DropStatement::~DropStatement() {
|
||||||
delete name;
|
free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteStatement
|
// ExecuteStatement
|
||||||
|
@ -65,8 +71,14 @@ namespace hsql {
|
||||||
parameters(NULL) {}
|
parameters(NULL) {}
|
||||||
|
|
||||||
ExecuteStatement::~ExecuteStatement() {
|
ExecuteStatement::~ExecuteStatement() {
|
||||||
delete name;
|
free(name);
|
||||||
delete parameters;
|
|
||||||
|
if (parameters != NULL) {
|
||||||
|
for (Expr* param : *parameters) {
|
||||||
|
delete param;
|
||||||
|
}
|
||||||
|
delete parameters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportStatement
|
// ImportStatement
|
||||||
|
@ -91,10 +103,22 @@ namespace hsql {
|
||||||
select(NULL) {}
|
select(NULL) {}
|
||||||
|
|
||||||
InsertStatement::~InsertStatement() {
|
InsertStatement::~InsertStatement() {
|
||||||
delete tableName;
|
free(tableName);
|
||||||
delete columns;
|
|
||||||
delete values;
|
|
||||||
delete select;
|
delete select;
|
||||||
|
|
||||||
|
if (columns != NULL) {
|
||||||
|
for (char* column : *columns) {
|
||||||
|
free(column);
|
||||||
|
}
|
||||||
|
delete columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values != NULL) {
|
||||||
|
for (Expr* expr : *values) {
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
delete values;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareStatement
|
// PrepareStatement
|
||||||
|
@ -105,7 +129,7 @@ namespace hsql {
|
||||||
|
|
||||||
PrepareStatement::~PrepareStatement() {
|
PrepareStatement::~PrepareStatement() {
|
||||||
delete query;
|
delete query;
|
||||||
delete name;
|
free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrepareStatement::setPlaceholders(std::vector<void*> ph) {
|
void PrepareStatement::setPlaceholders(std::vector<void*> ph) {
|
||||||
|
@ -114,7 +138,7 @@ namespace hsql {
|
||||||
placeholders.push_back((Expr*) e);
|
placeholders.push_back((Expr*) e);
|
||||||
}
|
}
|
||||||
// Sort by col-id
|
// Sort by col-id
|
||||||
std::sort(placeholders.begin(), placeholders.end(), [](Expr * i, Expr * j) -> bool { return (i->ival < j->ival); });
|
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
||||||
|
|
||||||
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||||
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||||
|
@ -142,8 +166,14 @@ namespace hsql {
|
||||||
having(NULL) {}
|
having(NULL) {}
|
||||||
|
|
||||||
GroupByDescription::~GroupByDescription() {
|
GroupByDescription::~GroupByDescription() {
|
||||||
delete columns;
|
|
||||||
delete having;
|
delete having;
|
||||||
|
|
||||||
|
if (columns != NULL) {
|
||||||
|
for (Expr* expr : *columns) {
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
delete columns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectStatement
|
// SelectStatement
|
||||||
|
@ -160,11 +190,19 @@ namespace hsql {
|
||||||
|
|
||||||
SelectStatement::~SelectStatement() {
|
SelectStatement::~SelectStatement() {
|
||||||
delete fromTable;
|
delete fromTable;
|
||||||
delete selectList;
|
|
||||||
delete whereClause;
|
delete whereClause;
|
||||||
delete groupBy;
|
delete groupBy;
|
||||||
|
delete unionSelect;
|
||||||
delete order;
|
delete order;
|
||||||
delete limit;
|
delete limit;
|
||||||
|
|
||||||
|
// Delete each element in the select list.
|
||||||
|
if (selectList != NULL) {
|
||||||
|
for (Expr* expr : *selectList) {
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
delete selectList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatement
|
// UpdateStatement
|
||||||
|
@ -176,8 +214,16 @@ namespace hsql {
|
||||||
|
|
||||||
UpdateStatement::~UpdateStatement() {
|
UpdateStatement::~UpdateStatement() {
|
||||||
delete table;
|
delete table;
|
||||||
delete updates;
|
|
||||||
delete where;
|
delete where;
|
||||||
|
|
||||||
|
if (updates != NULL) {
|
||||||
|
for (UpdateClause* update : *updates) {
|
||||||
|
free(update->column);
|
||||||
|
delete update->value;
|
||||||
|
delete update;
|
||||||
|
}
|
||||||
|
delete updates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableRef
|
// TableRef
|
||||||
|
@ -191,10 +237,19 @@ namespace hsql {
|
||||||
join(NULL) {}
|
join(NULL) {}
|
||||||
|
|
||||||
TableRef::~TableRef() {
|
TableRef::~TableRef() {
|
||||||
delete name;
|
free(schema);
|
||||||
delete alias;
|
free(name);
|
||||||
|
free(alias);
|
||||||
|
|
||||||
delete select;
|
delete select;
|
||||||
delete list;
|
delete join;
|
||||||
|
|
||||||
|
if (list != NULL) {
|
||||||
|
for (TableRef* table : *list) {
|
||||||
|
delete table;
|
||||||
|
}
|
||||||
|
delete list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TableRef::hasSchema() {
|
bool TableRef::hasSchema() {
|
||||||
|
|
|
@ -2,21 +2,21 @@
|
||||||
#define __HELPER_H__
|
#define __HELPER_H__
|
||||||
|
|
||||||
|
|
||||||
#define TEST_PARSE_SQL_QUERY(query, outputVar, numStatements) \
|
#define TEST_PARSE_SQL_QUERY(query, result, numStatements) \
|
||||||
const SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
|
const SQLParserResult* result = SQLParser::parseSQLString(query); \
|
||||||
ASSERT(outputVar->isValid()); \
|
ASSERT(result->isValid()); \
|
||||||
ASSERT_EQ(outputVar->size(), numStatements);
|
ASSERT_EQ(result->size(), numStatements);
|
||||||
|
|
||||||
|
|
||||||
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, outputVar) \
|
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \
|
||||||
TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \
|
TEST_PARSE_SQL_QUERY(query, result, 1); \
|
||||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmtType); \
|
ASSERT_EQ(result->getStatement(0)->type(), stmtType); \
|
||||||
const stmtClass* outputVar = (const stmtClass*) stmt_list->getStatement(0);
|
const stmtClass* outputVar = (const stmtClass*) result->getStatement(0);
|
||||||
|
|
||||||
|
|
||||||
#define TEST_CAST_STMT(stmt_list, stmt_index, stmtType, stmtClass, outputVar) \
|
#define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \
|
||||||
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmtType); \
|
ASSERT_EQ(result->getStatement(stmt_index)->type(), stmtType); \
|
||||||
const stmtClass* outputVar = (const stmtClass*) stmt_list->getStatement(stmt_index);
|
const stmtClass* outputVar = (const stmtClass*) result->getStatement(stmt_index);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,15 +7,28 @@
|
||||||
using namespace hsql;
|
using namespace hsql;
|
||||||
|
|
||||||
TEST(SelectTest) {
|
TEST(SelectTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT * FROM students;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
ASSERT_NULL(stmt->whereClause);
|
ASSERT_NULL(stmt->whereClause);
|
||||||
ASSERT_NULL(stmt->groupBy);
|
ASSERT_NULL(stmt->groupBy);
|
||||||
|
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectHavingTest) {
|
TEST(SelectHavingTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
ASSERT_FALSE(stmt->selectDistinct);
|
ASSERT_FALSE(stmt->selectDistinct);
|
||||||
|
|
||||||
GroupByDescription* group = stmt->groupBy;
|
GroupByDescription* group = stmt->groupBy;
|
||||||
|
@ -24,23 +37,39 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectDistinctTest) {
|
TEST(SelectDistinctTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT DISTINCT grade, city FROM students;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
ASSERT(stmt->selectDistinct);
|
ASSERT(stmt->selectDistinct);
|
||||||
ASSERT_NULL(stmt->whereClause);
|
ASSERT_NULL(stmt->whereClause);
|
||||||
|
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectGroupDistinctTest) {
|
TEST(SelectGroupDistinctTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
ASSERT_FALSE(stmt->selectDistinct);
|
ASSERT_FALSE(stmt->selectDistinct);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,13 @@ class TestsManager {
|
||||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||||
public:
|
public:
|
||||||
static std::vector<std::string>& testNames() {
|
static std::vector<std::string>& testNames() {
|
||||||
static std::vector<std::string>* _testNames = new std::vector<std::string>;
|
static std::vector<std::string> testNames;
|
||||||
return *_testNames;
|
return testNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<void (*)(void)>& tests() {
|
static std::vector<void (*)(void)>& tests() {
|
||||||
static std::vector<void (*)(void)>* tests = new std::vector<void (*)(void)>;
|
static std::vector<void (*)(void)> tests;
|
||||||
return *tests;
|
return tests;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
|
|
||||||
|
|
||||||
#define TEST(name) \
|
#define TEST(name) \
|
||||||
void name(); \
|
void name();\
|
||||||
namespace g_dummy { int _##name = AddTest(name, #name); } \
|
namespace g_dummy {\
|
||||||
|
int _##name = AddTest(name, #name);\
|
||||||
|
}\
|
||||||
void name()
|
void name()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5
|
||||||
(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10);
|
(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10);
|
||||||
SELECT * FROM "table" LIMIT 10 OFFSET 10; SELECT * FROM second;
|
SELECT * FROM "table" LIMIT 10 OFFSET 10; SELECT * FROM second;
|
||||||
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
|
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
|
||||||
# SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
|
-- SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
|
||||||
# JOIN
|
# JOIN
|
||||||
SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5
|
SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5
|
||||||
SELECT * FROM t1 JOIN t2 ON c1 = c2;
|
SELECT * FROM t1 JOIN t2 ON c1 = c2;
|
||||||
|
@ -37,3 +37,10 @@ PREPARE prep2 { INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?
|
||||||
EXECUTE prep_inst(1, 2, 3);
|
EXECUTE prep_inst(1, 2, 3);
|
||||||
EXECUTE prep;
|
EXECUTE prep;
|
||||||
DEALLOCATE PREPARE prep;
|
DEALLOCATE PREPARE prep;
|
||||||
|
# Error expeced
|
||||||
|
!
|
||||||
|
!1
|
||||||
|
!gibberish;
|
||||||
|
!SELECT abc;
|
||||||
|
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1
|
||||||
|
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
|
@ -18,9 +18,12 @@ std::vector<std::string> readlines(std::string path) {
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
|
|
||||||
// Skip comments
|
// Skip comments
|
||||||
if (line[0] != '#') {
|
if (line[0] == '#' ||
|
||||||
lines.push_back(line);
|
(line[0] == '-' && line[1] == '-')) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
@ -33,14 +36,14 @@ int main(int argc, char *argv[]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expectFalse = false;
|
bool globalExpectFalse = false;
|
||||||
bool useFile = false;
|
bool useFile = false;
|
||||||
std::string filePath = "";
|
std::string filePath = "";
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (; i < argc; ++i) {
|
for (; i < argc; ++i) {
|
||||||
if (STREQ(argv[i], "--false")) expectFalse = true;
|
if (STREQ(argv[i], "--false")) globalExpectFalse = true;
|
||||||
else if (STREQ(argv[i], "-f")) {
|
else if (STREQ(argv[i], "-f")) {
|
||||||
useFile = true;
|
useFile = true;
|
||||||
filePath = argv[++i];
|
filePath = argv[++i];
|
||||||
|
@ -62,6 +65,12 @@ int main(int argc, char *argv[]) {
|
||||||
// Execute queries
|
// Execute queries
|
||||||
int numFailed = 0;
|
int numFailed = 0;
|
||||||
for (std::string sql : queries) {
|
for (std::string sql : queries) {
|
||||||
|
bool expectFalse = globalExpectFalse;
|
||||||
|
if (sql.at(0) == '!') {
|
||||||
|
expectFalse = !expectFalse;
|
||||||
|
sql = sql.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Measuring the parsing time
|
// Measuring the parsing time
|
||||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||||
start = std::chrono::system_clock::now();
|
start = std::chrono::system_clock::now();
|
||||||
|
@ -82,6 +91,8 @@ int main(int argc, char *argv[]) {
|
||||||
// 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) {
|
||||||
|
|
|
@ -22,6 +22,8 @@ TEST(DeleteStatementTest) {
|
||||||
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) {
|
||||||
|
@ -43,6 +45,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,25 +73,40 @@ TEST(UpdateStatementTest) {
|
||||||
ASSERT(stmt->where->isType(kExprOperator));
|
ASSERT(stmt->where->isType(kExprOperator));
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(InsertStatementTest) {
|
TEST(InsertStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)", kStmtInsert, InsertStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
|
||||||
|
kStmtInsert,
|
||||||
|
InsertStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
ASSERT_EQ(stmt->values->size(), 4);
|
ASSERT_EQ(stmt->values->size(), 4);
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(DropTableStatementTest) {
|
TEST(DropTableStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("DROP TABLE students", kStmtDrop, DropStatement, stmt);
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"DROP TABLE students",
|
||||||
|
kStmtDrop,
|
||||||
|
DropStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,12 +153,16 @@ TEST(PrepareStatementTest) {
|
||||||
// Deallocate Statement
|
// Deallocate Statement
|
||||||
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
||||||
ASSERT_STREQ(drop->name, "stmt");
|
ASSERT_STREQ(drop->name, "stmt");
|
||||||
|
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(ExecuteStatementTest) {
|
TEST(ExecuteStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, stmt);
|
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
|
||||||
|
|
||||||
ASSERT_STREQ(stmt->name, "test");
|
ASSERT_STREQ(stmt->name, "test");
|
||||||
ASSERT_EQ(stmt->parameters->size(), 2);
|
ASSERT_EQ(stmt->parameters->size(), 2);
|
||||||
|
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
25
test/test.sh
25
test/test.sh
|
@ -1,15 +1,28 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# has to be executed from the root of the repository
|
# Has to be executed from the root of the repository.
|
||||||
|
# Usually invoked by `make test`.
|
||||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
||||||
|
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
# Running the tests.
|
||||||
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
|
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
|
||||||
RET1=$?
|
RET=$(($RET + $?))
|
||||||
|
|
||||||
bin/sql_tests
|
bin/sql_tests
|
||||||
RET2=$?
|
RET=$(($RET + $?))
|
||||||
|
|
||||||
if [[ $RET1 != 0 ]]; then exit $RET1; fi
|
# Running memory leak checks.
|
||||||
if [[ $RET2 != 0 ]]; then exit $RET2; fi
|
echo ""
|
||||||
|
echo "Running memory leak checks..."
|
||||||
|
|
||||||
exit 0
|
valgrind --leak-check=full --error-exitcode=1 \
|
||||||
|
./bin/sql_grammar_test -f "test/lib/valid_queries.sql" >> /dev/null
|
||||||
|
RET=$(($RET + $?))
|
||||||
|
|
||||||
|
valgrind --leak-check=full --error-exitcode=1 \
|
||||||
|
./bin/sql_tests -f "test/lib/valid_queries.sql" >> /dev/null
|
||||||
|
RET=$(($RET + $?))
|
||||||
|
|
||||||
|
exit $RET
|
||||||
|
|
Loading…
Reference in New Issue