add astyle formatting

This commit is contained in:
Pedro 2016-02-27 15:01:06 +01:00
parent 57b8cdd31b
commit 7d1c56d0aa
27 changed files with 928 additions and 851 deletions

3
.gitignore vendored
View File

@ -31,3 +31,6 @@ lib-test/
*.exe *.exe
*.out *.out
*.app *.app
*.cpp.orig
*.h.orig

View File

@ -9,6 +9,9 @@ LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(S
LIBOBJ = $(LIBCPP:%.cpp=%.o) LIBOBJ = $(LIBCPP:%.cpp=%.o)
TESTCPP = $(shell find test/lib/ -name '*.cpp') TESTCPP = $(shell find test/lib/ -name '*.cpp')
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
# compile & link flages # compile & link flages
CC = g++ CC = g++
CFLAGS = -std=c++11 -Wall -fPIC CFLAGS = -std=c++11 -Wall -fPIC
@ -48,6 +51,10 @@ cleanall: clean cleanparser
install: install:
cp $(TARGET) $(INSTALL)/lib/$(TARGET) cp $(TARGET) $(INSTALL)/lib/$(TARGET)
format:
astyle --options=astyle.options $(ALLLIB)
astyle --options=astyle.options $(ALLTEST)
############ ############
### Test ### ### Test ###
############ ############
@ -63,5 +70,3 @@ $(BIN)/sql_tests: library
$(BIN)/sql_grammar_test: library $(BIN)/sql_grammar_test: library
@mkdir -p $(BIN)/ @mkdir -p $(BIN)/
$(CC) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser $(CC) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser

8
astyle.options Normal file
View File

@ -0,0 +1,8 @@
# indentation
--indent=spaces=4
--indent-namespaces
--style=java
--style=attach
-A2

View File

@ -8,39 +8,39 @@
namespace hsql { namespace hsql {
SQLParser::SQLParser() { SQLParser::SQLParser() {
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) { SQLParserResult* SQLParser::parseSQLString(const char *text) {
SQLParserResult* result = NULL; SQLParserResult* result = NULL;
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 // couldn't initialize
fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n"); fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n");
return NULL; return NULL;
} }
state = hsql__scan_string(text, scanner); state = hsql__scan_string(text, scanner);
if (hsql_parse(&result, scanner)) { if (hsql_parse(&result, scanner)) {
// Returns an error stmt object // Returns an error stmt object
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;
} }
SQLParserResult* SQLParser::parseSQLString(const std::string& text) { SQLParserResult* SQLParser::parseSQLString(const std::string& text) {
return parseSQLString(text.c_str()); return parseSQLString(text.c_str());
} }
} // namespace hsql } // namespace hsql

View File

@ -5,17 +5,17 @@
#include "sql/statements.h" #include "sql/statements.h"
namespace hsql { namespace hsql {
/** /**
* Main class for parsing SQL strings * Main class for parsing SQL strings
*/ */
class SQLParser { class SQLParser {
public: public:
static SQLParserResult* parseSQLString(const char* sql); static SQLParserResult* parseSQLString(const char* sql);
static SQLParserResult* parseSQLString(const std::string& sql); static SQLParserResult* parseSQLString(const std::string& sql);
private: private:
SQLParser(); SQLParser();
}; };
} // namespace hsql } // namespace hsql

View File

@ -3,39 +3,39 @@
namespace hsql { namespace hsql {
SQLParserResult::SQLParserResult() : SQLParserResult::SQLParserResult() :
isValid(true), isValid(true),
errorMsg(NULL) {}; errorMsg(NULL) {};
SQLParserResult::SQLParserResult(SQLStatement* stmt) : SQLParserResult::SQLParserResult(SQLStatement* stmt) :
isValid(true), isValid(true),
errorMsg(NULL) { errorMsg(NULL) {
addStatement(stmt); addStatement(stmt);
}; };
SQLParserResult::~SQLParserResult() { SQLParserResult::~SQLParserResult() {
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) { for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
delete *it; delete *it;
} }
delete errorMsg; delete errorMsg;
} }
void SQLParserResult::addStatement(SQLStatement* stmt) { void SQLParserResult::addStatement(SQLStatement* stmt) {
statements.push_back(stmt); statements.push_back(stmt);
} }
SQLStatement* SQLParserResult::getStatement(int id) { SQLStatement* SQLParserResult::getStatement(int id) {
return statements[id]; return statements[id];
} }
size_t SQLParserResult::size() { size_t SQLParserResult::size() {
return statements.size(); return statements.size();
} }
} // namespace hsql } // namespace hsql

View File

@ -4,31 +4,31 @@
#include "sql/SQLStatement.h" #include "sql/SQLStatement.h"
namespace hsql { namespace hsql {
/** /**
* Represents the result of the SQLParser. * Represents the result of the SQLParser.
* If parsing was successful it contains a list of SQLStatement. * If parsing was successful it contains a list of SQLStatement.
*/ */
class SQLParserResult { class SQLParserResult {
public: public:
SQLParserResult(); SQLParserResult();
SQLParserResult(SQLStatement* stmt); SQLParserResult(SQLStatement* stmt);
virtual ~SQLParserResult(); virtual ~SQLParserResult();
void addStatement(SQLStatement* stmt); void addStatement(SQLStatement* stmt);
SQLStatement* getStatement(int id); SQLStatement* getStatement(int id);
size_t size(); size_t size();
// public properties // public properties
std::vector<SQLStatement*> statements; std::vector<SQLStatement*> statements;
bool isValid; bool isValid;
const char* errorMsg; const char* errorMsg;
int errorLine; int errorLine;
int errorColumn; int errorColumn;
}; };
} // namespace hsql } // namespace hsql

View File

@ -5,62 +5,62 @@
namespace hsql { namespace hsql {
/** /**
* @struct ColumnDefinition * @struct ColumnDefinition
* @brief Represents definition of a table column * @brief Represents definition of a table column
*/ */
struct ColumnDefinition { struct ColumnDefinition {
enum DataType { enum DataType {
TEXT, TEXT,
INT, INT,
DOUBLE DOUBLE
}; };
ColumnDefinition(char* name, DataType type) : ColumnDefinition(char* name, DataType type) :
name(name), name(name),
type(type) {} type(type) {}
virtual ~ColumnDefinition() { virtual ~ColumnDefinition() {
delete name; delete name;
} }
char* name; char* name;
DataType type; DataType type;
}; };
/** /**
* @struct CreateStatement * @struct CreateStatement
* @brief Represents "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)" * @brief Represents "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
*/ */
struct CreateStatement : SQLStatement { struct CreateStatement : SQLStatement {
enum CreateType { enum CreateType {
kTable, kTable,
kTableFromTbl, // Hyrise file format kTableFromTbl, // Hyrise file format
}; };
CreateStatement(CreateType type) : CreateStatement(CreateType type) :
SQLStatement(kStmtCreate), SQLStatement(kStmtCreate),
type(type), type(type),
if_not_exists(false), if_not_exists(false),
columns(NULL), columns(NULL),
file_path(NULL), file_path(NULL),
table_name(NULL) {}; table_name(NULL) {};
virtual ~CreateStatement() { virtual ~CreateStatement() {
delete columns; delete columns;
delete file_path; delete file_path;
delete table_name; delete table_name;
} }
CreateType type; CreateType type;
bool if_not_exists; bool if_not_exists;
std::vector<ColumnDefinition*>* columns; std::vector<ColumnDefinition*>* columns;
const char* file_path; const char* file_path;
const char* table_name; const char* table_name;
}; };

View File

@ -6,27 +6,27 @@
namespace hsql { namespace hsql {
/** /**
* @struct DeleteStatement * @struct DeleteStatement
* @brief Represents "DELETE FROM students WHERE grade > 3.0" * @brief Represents "DELETE FROM students WHERE grade > 3.0"
* *
* If expr == NULL => delete all rows (truncate) * If expr == NULL => delete all rows (truncate)
*/ */
struct DeleteStatement : SQLStatement { struct DeleteStatement : SQLStatement {
DeleteStatement() : DeleteStatement() :
SQLStatement(kStmtDelete), SQLStatement(kStmtDelete),
table_name(NULL), table_name(NULL),
expr(NULL) {}; expr(NULL) {};
virtual ~DeleteStatement() { virtual ~DeleteStatement() {
delete table_name; delete table_name;
delete expr; delete expr;
} }
char* table_name; char* table_name;
Expr* expr; Expr* expr;
}; };

View File

@ -6,33 +6,33 @@
namespace hsql { namespace hsql {
/** /**
* @struct DropStatement * @struct DropStatement
* @brief Represents "DROP TABLE" * @brief Represents "DROP TABLE"
*/ */
struct DropStatement : SQLStatement { struct DropStatement : SQLStatement {
enum EntityType { enum EntityType {
kTable, kTable,
kSchema, kSchema,
kIndex, kIndex,
kView, kView,
kPreparedStatement kPreparedStatement
}; };
DropStatement(EntityType type) : DropStatement(EntityType type) :
SQLStatement(kStmtDrop), SQLStatement(kStmtDrop),
type(type), type(type),
name(NULL) {} name(NULL) {}
virtual ~DropStatement() { virtual ~DropStatement() {
delete name; delete name;
} }
EntityType type; EntityType type;
const char* name; const char* name;
}; };

View File

@ -6,24 +6,24 @@
namespace hsql { namespace hsql {
/** /**
* @struct ExecuteStatement * @struct ExecuteStatement
* @brief Represents "EXECUTE ins_prep(100, "test", 2.3);" * @brief Represents "EXECUTE ins_prep(100, "test", 2.3);"
*/ */
struct ExecuteStatement : SQLStatement { struct ExecuteStatement : SQLStatement {
ExecuteStatement() : ExecuteStatement() :
SQLStatement(kStmtExecute), SQLStatement(kStmtExecute),
name(NULL), name(NULL),
parameters(NULL) {} parameters(NULL) {}
virtual ~ExecuteStatement() { virtual ~ExecuteStatement() {
delete name; delete name;
delete parameters; delete parameters;
} }
const char* name; const char* name;
std::vector<Expr*>* parameters; std::vector<Expr*>* parameters;
}; };

View File

@ -5,98 +5,98 @@
namespace hsql { 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 = new char[len+1];
strncpy(copy, source+from, len); strncpy(copy, source+from, len);
copy[len] = '\0'; copy[len] = '\0';
return copy; return copy;
} }
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) { Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->op_type = op; e->op_type = op;
e->expr = expr; e->expr = expr;
e->expr2 = NULL; e->expr2 = NULL;
return e; return e;
} }
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) { Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
Expr* e = new Expr(kExprOperator); Expr* e = new Expr(kExprOperator);
e->op_type = op; e->op_type = op;
e->op_char = 0; e->op_char = 0;
e->expr = expr1; e->expr = expr1;
e->expr2 = expr2; e->expr2 = expr2;
return e; return e;
} }
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->op_type = SIMPLE_OP; e->op_type = SIMPLE_OP;
e->op_char = op; e->op_char = op;
e->expr = expr1; e->expr = expr1;
e->expr2 = expr2; e->expr2 = expr2;
return e; return e;
} }
Expr* Expr::makeLiteral(int64_t val) { Expr* Expr::makeLiteral(int64_t val) {
Expr* e = new Expr(kExprLiteralInt); Expr* e = new Expr(kExprLiteralInt);
e->ival = val; e->ival = val;
return e; return e;
} }
Expr* Expr::makeLiteral(double value) { Expr* Expr::makeLiteral(double value) {
Expr* e = new Expr(kExprLiteralFloat); Expr* e = new Expr(kExprLiteralFloat);
e->fval = value; e->fval = value;
return e; return e;
} }
Expr* Expr::makeLiteral(char* string) { Expr* Expr::makeLiteral(char* string) {
Expr* e = new Expr(kExprLiteralString); Expr* e = new Expr(kExprLiteralString);
e->name = string; e->name = string;
return e; return e;
} }
Expr* Expr::makeColumnRef(char* name) { Expr* Expr::makeColumnRef(char* name) {
Expr* e = new Expr(kExprColumnRef); Expr* e = new Expr(kExprColumnRef);
e->name = name; e->name = name;
return e; return e;
} }
Expr* Expr::makeColumnRef(char* table, char* name) { Expr* Expr::makeColumnRef(char* table, char* name) {
Expr* e = new Expr(kExprColumnRef); Expr* e = new Expr(kExprColumnRef);
e->name = name; e->name = name;
e->table = table; e->table = table;
return e; return e;
} }
Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) { Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) {
Expr* e = new Expr(kExprFunctionRef); Expr* e = new Expr(kExprFunctionRef);
e->name = func_name; e->name = func_name;
e->expr = expr; e->expr = expr;
e->distinct = distinct; e->distinct = distinct;
return e; return e;
} }
Expr* Expr::makePlaceholder(int id) { Expr* Expr::makePlaceholder(int id) {
Expr* e = new Expr(kExprPlaceholder); Expr* e = new Expr(kExprPlaceholder);
e->ival = id; e->ival = id;
return e; return e;
} }
Expr::~Expr() { Expr::~Expr() {
delete expr; delete expr;
delete expr2; delete expr2;
delete name; delete name;
delete table; delete table;
} }
} // namespace hsql } // namespace hsql

View File

@ -7,115 +7,127 @@
namespace hsql { namespace hsql {
// Helper function // Helper function
char* substr(const char* source, int from, int to); char* substr(const char* source, int from, int to);
typedef enum { typedef enum {
kExprLiteralFloat, kExprLiteralFloat,
kExprLiteralString, kExprLiteralString,
kExprLiteralInt, kExprLiteralInt,
kExprStar, kExprStar,
kExprPlaceholder, kExprPlaceholder,
kExprColumnRef, kExprColumnRef,
kExprFunctionRef, kExprFunctionRef,
kExprOperator kExprOperator
} ExprType; } ExprType;
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 * Operator types. These are important for expressions of type kExprOperator
* Trivial types are those that can be described by a single character e.g: * Trivial types are those that can be described by a single character e.g:
* + - * / < > = % * + - * / < > = %
* Non-trivial are: * Non-trivial are:
* <> <= >= LIKE ISNULL NOT * <> <= >= LIKE ISNULL NOT
*/ */
typedef enum { typedef enum {
SIMPLE_OP, SIMPLE_OP,
// Binary // Binary
NOT_EQUALS, NOT_EQUALS,
LESS_EQ, LESS_EQ,
GREATER_EQ, GREATER_EQ,
LIKE, LIKE,
NOT_LIKE, NOT_LIKE,
AND, AND,
OR, OR,
// Unary // Unary
NOT, NOT,
UMINUS, UMINUS,
ISNULL ISNULL
} OperatorType; } OperatorType;
Expr(ExprType type) : Expr(ExprType type) :
type(type), type(type),
expr(NULL), expr(NULL),
expr2(NULL), expr2(NULL),
name(NULL), name(NULL),
table(NULL), table(NULL),
alias(NULL) {}; alias(NULL) {};
// Interesting side-effect: // Interesting side-effect:
// Making the destructor virtual used to cause segmentation faults // Making the destructor virtual used to cause segmentation faults
~Expr(); ~Expr();
ExprType type; ExprType type;
Expr* expr; Expr* expr;
Expr* expr2; Expr* expr2;
char* name; char* name;
char* table; char* table;
char* alias; char* alias;
float fval; float fval;
int64_t ival; int64_t ival;
int64_t ival2; int64_t ival2;
OperatorType op_type; OperatorType op_type;
char op_char; char op_char;
bool distinct; bool distinct;
/** /**
* Convenience accessor methods * Convenience accessor methods
*/ */
inline bool isType(ExprType e_type) { return e_type == type; } inline bool isType(ExprType e_type) {
inline bool isLiteral() { return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder); } return e_type == type;
inline bool hasAlias() { return alias != NULL; } }
inline bool hasTable() { return table != NULL; } inline bool isLiteral() {
inline char* getName() { return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
if (alias != NULL) return alias; }
else return name; inline bool hasAlias() {
} return alias != NULL;
inline bool isSimpleOp() { return op_type == SIMPLE_OP; } }
inline bool isSimpleOp(char op) { return isSimpleOp() && op_char == op; } inline bool hasTable() {
return table != NULL;
}
inline char* getName() {
if (alias != NULL) return alias;
else return name;
}
inline bool isSimpleOp() {
return op_type == SIMPLE_OP;
}
inline bool isSimpleOp(char op) {
return isSimpleOp() && op_char == op;
}
/** /**
* Static expression constructors * Static expression constructors
*/ */
static Expr* makeOpUnary(OperatorType op, Expr* expr); static Expr* makeOpUnary(OperatorType op, Expr* expr);
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2); static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2); static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
static Expr* makeLiteral(int64_t val); static Expr* makeLiteral(int64_t val);
static Expr* makeLiteral(double val); static Expr* makeLiteral(double val);
static Expr* makeLiteral(char* val); static Expr* makeLiteral(char* val);
static Expr* makeColumnRef(char* name); static Expr* makeColumnRef(char* name);
static Expr* makeColumnRef(char* table, char* name); static Expr* makeColumnRef(char* table, char* name);
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct); static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
static Expr* makePlaceholder(int id); static Expr* makePlaceholder(int id);
}; };
// Zero initializes an Expr object and assigns it to a space in the heap // Zero initializes an Expr object and assigns it to a space in the heap
// For Hyrise we still had to put in the explicit NULL constructor // For Hyrise we still had to put in the explicit NULL constructor

View File

@ -8,33 +8,33 @@ namespace hsql {
/** /**
* @struct ImportStatement * @struct ImportStatement
* @brief Represents "IMPORT" * @brief Represents "IMPORT"
*/ */
struct ImportStatement : SQLStatement { struct ImportStatement : SQLStatement {
enum ImportType { enum ImportType {
kImportCSV, kImportCSV,
kImportTbl, // Hyrise file format kImportTbl, // Hyrise file format
}; };
ImportStatement(ImportType type) : ImportStatement(ImportType type) :
SQLStatement(kStmtImport), SQLStatement(kStmtImport),
type(type), type(type),
file_path(NULL), file_path(NULL),
table_name(NULL) {}; table_name(NULL) {};
virtual ~ImportStatement() { virtual ~ImportStatement() {
delete file_path; delete file_path;
delete table_name; delete table_name;
} }
ImportType type; ImportType type;
const char* file_path; const char* file_path;
const char* table_name; const char* table_name;
}; };

View File

@ -7,37 +7,37 @@
namespace hsql { namespace hsql {
/** /**
* @struct InsertStatement * @struct InsertStatement
* @brief Represents "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)" * @brief Represents "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
*/ */
struct InsertStatement : SQLStatement { struct InsertStatement : SQLStatement {
enum InsertType { enum InsertType {
kInsertValues, kInsertValues,
kInsertSelect kInsertSelect
}; };
InsertStatement(InsertType type) : InsertStatement(InsertType type) :
SQLStatement(kStmtInsert), SQLStatement(kStmtInsert),
type(type), type(type),
table_name(NULL), table_name(NULL),
columns(NULL), columns(NULL),
values(NULL), values(NULL),
select(NULL) {} select(NULL) {}
virtual ~InsertStatement() { virtual ~InsertStatement() {
delete table_name; delete table_name;
delete columns; delete columns;
delete values; delete values;
delete select; delete select;
} }
InsertType type; InsertType type;
const char* table_name; const char* table_name;
std::vector<char*>* columns; std::vector<char*>* columns;
std::vector<Expr*>* values; std::vector<Expr*>* values;
SelectStatement* select; SelectStatement* select;
}; };

View File

@ -9,43 +9,43 @@
namespace hsql { namespace hsql {
/** /**
* @struct PrepareStatement * @struct PrepareStatement
* @brief Represents "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?" * @brief Represents "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
*/ */
struct PrepareStatement : SQLStatement { struct PrepareStatement : SQLStatement {
PrepareStatement() : PrepareStatement() :
SQLStatement(kStmtPrepare), SQLStatement(kStmtPrepare),
name(NULL), name(NULL),
query(NULL) {} query(NULL) {}
virtual ~PrepareStatement() { virtual ~PrepareStatement() {
delete query; delete query;
delete name; delete name;
} }
/** /**
* @param vector of placeholders that the parser found * @param vector of placeholders that the parser found
* *
* When setting the placeholders we need to make sure that they are in the correct order. * When setting the placeholders we need to make sure that they are in the correct order.
* To ensure that, during parsing we store the character position use that to sort the list here. * To ensure that, during parsing we store the character position use that to sort the list here.
*/ */
void setPlaceholders(std::vector<void*> ph) { void setPlaceholders(std::vector<void*> ph) {
for (void* e : ph) { for (void* e : ph) {
if (e != NULL) if (e != NULL)
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 (uint i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i; for (uint i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
} }
const char* name; const char* name;
SQLParserResult* query; SQLParserResult* query;
std::vector<Expr*> placeholders; std::vector<Expr*> placeholders;
}; };

View File

@ -6,37 +6,39 @@
namespace hsql { namespace hsql {
typedef enum { typedef enum {
kStmtError, // unused kStmtError, // unused
kStmtSelect, kStmtSelect,
kStmtImport, kStmtImport,
kStmtInsert, kStmtInsert,
kStmtUpdate, kStmtUpdate,
kStmtDelete, kStmtDelete,
kStmtCreate, kStmtCreate,
kStmtDrop, kStmtDrop,
kStmtPrepare, kStmtPrepare,
kStmtExecute, kStmtExecute,
kStmtExport, kStmtExport,
kStmtRename, kStmtRename,
kStmtAlter kStmtAlter
} StatementType; } StatementType;
/** /**
* Base struct for every SQL statement * Base struct for every SQL statement
*/ */
struct SQLStatement { struct SQLStatement {
SQLStatement(StatementType type) : SQLStatement(StatementType type) :
_type(type) {}; _type(type) {};
virtual ~SQLStatement() {} virtual ~SQLStatement() {}
virtual StatementType type() { return _type; } virtual StatementType type() {
return _type;
}
private: private:
StatementType _type; StatementType _type;
}; };
} // namespace hsql } // namespace hsql

View File

@ -9,98 +9,98 @@ namespace hsql {
/** /**
* @struct OrderDescription * @struct OrderDescription
* @brief Description of the order by clause within a select statement * @brief Description of the order by clause within a select statement
* *
* TODO: hold multiple expressions to be sorted by * TODO: hold multiple expressions to be sorted by
*/ */
typedef enum { typedef enum {
kOrderAsc, kOrderAsc,
kOrderDesc kOrderDesc
} OrderType; } OrderType;
struct OrderDescription { struct OrderDescription {
OrderDescription(OrderType type, Expr* expr) : OrderDescription(OrderType type, Expr* expr) :
type(type), type(type),
expr(expr) {} expr(expr) {}
virtual ~OrderDescription() { virtual ~OrderDescription() {
delete expr; delete expr;
} }
OrderType type; OrderType type;
Expr* expr; Expr* expr;
}; };
/** /**
* @struct LimitDescription * @struct LimitDescription
* @brief Description of the limit clause within a select statement * @brief Description of the limit clause within a select statement
*/ */
const int64_t kNoLimit = -1; const int64_t kNoLimit = -1;
const int64_t kNoOffset = -1; const int64_t kNoOffset = -1;
struct LimitDescription { struct LimitDescription {
LimitDescription(int64_t limit, int64_t offset) : LimitDescription(int64_t limit, int64_t offset) :
limit(limit), limit(limit),
offset(offset) {} offset(offset) {}
int64_t limit; int64_t limit;
int64_t offset; int64_t offset;
}; };
/** /**
* @struct GroupByDescription * @struct GroupByDescription
*/ */
struct GroupByDescription { struct GroupByDescription {
GroupByDescription() : GroupByDescription() :
columns(NULL), columns(NULL),
having(NULL) {} having(NULL) {}
~GroupByDescription() { ~GroupByDescription() {
delete columns; delete columns;
delete having; delete having;
} }
std::vector<Expr*>* columns; std::vector<Expr*>* columns;
Expr* having; Expr* having;
}; };
/** /**
* @struct SelectStatement * @struct SelectStatement
* @brief Representation of a full select statement. * @brief Representation of a full select statement.
* *
* TODO: add union_order and union_limit * TODO: add union_order and union_limit
*/ */
struct SelectStatement : SQLStatement { struct SelectStatement : SQLStatement {
SelectStatement() : SelectStatement() :
SQLStatement(kStmtSelect), SQLStatement(kStmtSelect),
from_table(NULL), from_table(NULL),
select_list(NULL), select_list(NULL),
where_clause(NULL), where_clause(NULL),
group_by(NULL), group_by(NULL),
union_select(NULL), union_select(NULL),
order(NULL), order(NULL),
limit(NULL) {}; limit(NULL) {};
virtual ~SelectStatement() { virtual ~SelectStatement() {
delete from_table; delete from_table;
delete select_list; delete select_list;
delete where_clause; delete where_clause;
delete group_by; delete group_by;
delete order; delete order;
delete limit; delete limit;
} }
TableRef* from_table; TableRef* from_table;
bool select_distinct; bool select_distinct;
std::vector<Expr*>* select_list; std::vector<Expr*>* select_list;
Expr* where_clause; Expr* where_clause;
GroupByDescription* group_by; GroupByDescription* group_by;
SelectStatement* union_select; SelectStatement* union_select;
OrderDescription* order; OrderDescription* order;
LimitDescription* limit; LimitDescription* limit;
}; };
} // namespace hsql } // namespace hsql

View File

@ -7,97 +7,99 @@
namespace hsql { namespace hsql {
struct SelectStatement; struct SelectStatement;
struct JoinDefinition; struct JoinDefinition;
struct TableRef; struct TableRef;
/** /**
* @enum TableRefType * @enum TableRefType
* Types table references * Types table references
*/ */
typedef enum { typedef enum {
kTableName, kTableName,
kTableSelect, kTableSelect,
kTableJoin, kTableJoin,
kTableCrossProduct kTableCrossProduct
} TableRefType; } TableRefType;
/** /**
* @struct TableRef * @struct TableRef
* @brief Holds reference to tables. Can be either table names or a select statement. * @brief Holds reference to tables. Can be either table names or a select statement.
*/ */
struct TableRef { struct TableRef {
TableRef(TableRefType type) : TableRef(TableRefType type) :
type(type), type(type),
schema(NULL), schema(NULL),
name(NULL), name(NULL),
alias(NULL), alias(NULL),
select(NULL), select(NULL),
list(NULL), list(NULL),
join(NULL) {} join(NULL) {}
virtual ~TableRef(); virtual ~TableRef();
TableRefType type; TableRefType type;
char* schema; char* schema;
char* name; char* name;
char* alias; char* alias;
SelectStatement* select; SelectStatement* select;
std::vector<TableRef*>* list; std::vector<TableRef*>* list;
JoinDefinition* join; JoinDefinition* join;
/** /**
* Convenience accessor methods * Convenience accessor methods
*/ */
inline bool hasSchema() { return schema != NULL; } inline bool hasSchema() {
return schema != NULL;
}
inline char* getName() { inline char* getName() {
if (alias != NULL) return alias; if (alias != NULL) return alias;
else return name; else return name;
} }
}; };
/** /**
* @enum JoinType * @enum JoinType
* Types of joins * Types of joins
*/ */
typedef enum { typedef enum {
kJoinInner, kJoinInner,
kJoinOuter, kJoinOuter,
kJoinLeft, kJoinLeft,
kJoinRight, kJoinRight,
} JoinType; } JoinType;
/** /**
* @struct JoinDefinition * @struct JoinDefinition
* @brief Definition of a join table * @brief Definition of a join table
*/ */
struct JoinDefinition { struct JoinDefinition {
JoinDefinition() : JoinDefinition() :
left(NULL), left(NULL),
right(NULL), right(NULL),
condition(NULL), condition(NULL),
type(kJoinInner) {} type(kJoinInner) {}
virtual ~JoinDefinition() { virtual ~JoinDefinition() {
delete left; delete left;
delete right; delete right;
delete condition; delete condition;
} }
TableRef* left; TableRef* left;
TableRef* right; TableRef* right;
Expr* condition; Expr* condition;
JoinType type; JoinType type;
}; };

View File

@ -6,38 +6,38 @@
namespace hsql { namespace hsql {
/** /**
* @struct UpdateClause * @struct UpdateClause
* @brief Represents "column = value" expressions * @brief Represents "column = value" expressions
*/ */
struct UpdateClause { struct UpdateClause {
char* column; char* column;
Expr* value; Expr* value;
}; };
/** /**
* @struct UpdateStatement * @struct UpdateStatement
* @brief Represents "UPDATE" * @brief Represents "UPDATE"
*/ */
struct UpdateStatement : SQLStatement { struct UpdateStatement : SQLStatement {
UpdateStatement() : UpdateStatement() :
SQLStatement(kStmtUpdate), SQLStatement(kStmtUpdate),
table(NULL), table(NULL),
updates(NULL), updates(NULL),
where(NULL) {} where(NULL) {}
virtual ~UpdateStatement() { virtual ~UpdateStatement() {
delete table; delete table;
delete updates; delete updates;
delete where; delete where;
} }
// TODO: switch to char* instead of TableRef // TODO: switch to char* instead of TableRef
TableRef* table; TableRef* table;
std::vector<UpdateClause*>* updates; std::vector<UpdateClause*>* updates;
Expr* where; Expr* where;
}; };

View File

@ -5,12 +5,12 @@
namespace hsql { namespace hsql {
TableRef::~TableRef() { TableRef::~TableRef() {
delete name; delete name;
delete alias; delete alias;
delete select; delete select;
delete list; delete list;
} }
} // namespace hsql } // namespace hsql

View File

@ -5,159 +5,204 @@
namespace hsql { namespace hsql {
void printOperatorExpression(Expr* expr, uint num_indent); void printOperatorExpression(Expr* expr, uint num_indent);
std::string indent(uint num_indent) { return std::string(num_indent, '\t'); } std::string indent(uint num_indent) {
void inprint(int64_t val, uint num_indent) { printf("%s%ld \n", indent(num_indent).c_str(), val); } return std::string(num_indent, '\t');
void inprint(float val, uint num_indent) { printf("%s%f\n", indent(num_indent).c_str(), val); } }
void inprint(const char* val, uint num_indent) { printf("%s%s\n", indent(num_indent).c_str(), val); } void inprint(int64_t val, uint num_indent) {
void inprint(const char* val, const char* val2, uint num_indent) { printf("%s%s->%s\n", indent(num_indent).c_str(), val, val2); } printf("%s%ld \n", indent(num_indent).c_str(), val);
void inprintC(char val, uint num_indent) { printf("%s%c\n", indent(num_indent).c_str(), val); } }
void inprintU(uint64_t val, uint num_indent) { printf("%s%lu\n", indent(num_indent).c_str(), val); } void inprint(float val, uint num_indent) {
printf("%s%f\n", indent(num_indent).c_str(), val);
}
void inprint(const char* val, uint num_indent) {
printf("%s%s\n", indent(num_indent).c_str(), val);
}
void inprint(const char* val, const char* val2, uint num_indent) {
printf("%s%s->%s\n", indent(num_indent).c_str(), val, val2);
}
void inprintC(char val, uint num_indent) {
printf("%s%c\n", indent(num_indent).c_str(), val);
}
void inprintU(uint64_t val, uint num_indent) {
printf("%s%lu\n", indent(num_indent).c_str(), val);
}
void printTableRefInfo(TableRef* table, uint num_indent) { void printTableRefInfo(TableRef* table, uint num_indent) {
switch (table->type) { switch (table->type) {
case kTableName: case kTableName:
inprint(table->name, num_indent); inprint(table->name, num_indent);
break; break;
case kTableSelect: case kTableSelect:
printSelectStatementInfo(table->select, num_indent); printSelectStatementInfo(table->select, num_indent);
break; break;
case kTableJoin: case kTableJoin:
inprint("Join Table", num_indent); inprint("Join Table", num_indent);
inprint("Left", num_indent+1); inprint("Left", num_indent+1);
printTableRefInfo(table->join->left, num_indent+2); printTableRefInfo(table->join->left, num_indent+2);
inprint("Right", num_indent+1); inprint("Right", num_indent+1);
printTableRefInfo(table->join->right, num_indent+2); printTableRefInfo(table->join->right, num_indent+2);
inprint("Join Condition", num_indent+1); inprint("Join Condition", num_indent+1);
printExpression(table->join->condition, num_indent+2); printExpression(table->join->condition, num_indent+2);
break; break;
case kTableCrossProduct: case kTableCrossProduct:
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent); for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent);
break; break;
} }
if (table->alias != NULL) { if (table->alias != NULL) {
inprint("Alias", num_indent+1); inprint("Alias", num_indent+1);
inprint(table->alias, num_indent+2); inprint(table->alias, num_indent+2);
} }
} }
void printOperatorExpression(Expr* expr, uint num_indent) { void printOperatorExpression(Expr* expr, uint num_indent) {
if (expr == NULL) { inprint("null", num_indent); return; } if (expr == NULL) {
inprint("null", num_indent);
return;
}
switch (expr->op_type) { switch (expr->op_type) {
case Expr::SIMPLE_OP: inprintC(expr->op_char, num_indent); break; case Expr::SIMPLE_OP:
case Expr::AND: inprint("AND", num_indent); break; inprintC(expr->op_char, num_indent);
case Expr::OR: inprint("OR", num_indent); break; break;
case Expr::NOT: inprint("NOT", num_indent); break; case Expr::AND:
default: inprintU(expr->op_type, num_indent); break; inprint("AND", num_indent);
} break;
printExpression(expr->expr, num_indent+1); case Expr::OR:
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1); inprint("OR", num_indent);
} break;
case Expr::NOT:
inprint("NOT", num_indent);
break;
default:
inprintU(expr->op_type, num_indent);
break;
}
printExpression(expr->expr, num_indent+1);
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1);
}
void printExpression(Expr* expr, uint num_indent) { void printExpression(Expr* expr, uint num_indent) {
switch (expr->type) { switch (expr->type) {
case kExprStar: inprint("*", num_indent); break; case kExprStar:
case kExprColumnRef: inprint(expr->name, num_indent); break; inprint("*", num_indent);
// case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break; break;
case kExprLiteralFloat: inprint(expr->fval, num_indent); break; case kExprColumnRef:
case kExprLiteralInt: inprint(expr->ival, num_indent); break; inprint(expr->name, num_indent);
case kExprLiteralString: inprint(expr->name, num_indent); break; break;
case kExprFunctionRef: inprint(expr->name, num_indent); inprint(expr->expr->name, num_indent+1); break; // case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break;
case kExprOperator: printOperatorExpression(expr, num_indent); break; case kExprLiteralFloat:
default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return; inprint(expr->fval, num_indent);
} break;
if (expr->alias != NULL) { case kExprLiteralInt:
inprint("Alias", num_indent+1); inprint(expr->alias, num_indent+2); inprint(expr->ival, num_indent);
} break;
} case kExprLiteralString:
inprint(expr->name, num_indent);
break;
case kExprFunctionRef:
inprint(expr->name, num_indent);
inprint(expr->expr->name, num_indent+1);
break;
case kExprOperator:
printOperatorExpression(expr, num_indent);
break;
default:
fprintf(stderr, "Unrecognized expression type %d\n", expr->type);
return;
}
if (expr->alias != NULL) {
inprint("Alias", num_indent+1);
inprint(expr->alias, num_indent+2);
}
}
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) { void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
inprint("SelectStatement", num_indent); inprint("SelectStatement", num_indent);
inprint("Fields:", num_indent+1); inprint("Fields:", num_indent+1);
for (Expr* expr : *stmt->select_list) printExpression(expr, num_indent+2); for (Expr* expr : *stmt->select_list) printExpression(expr, num_indent+2);
inprint("Sources:", num_indent+1); inprint("Sources:", num_indent+1);
printTableRefInfo(stmt->from_table, num_indent+2); printTableRefInfo(stmt->from_table, num_indent+2);
if (stmt->where_clause != NULL) { if (stmt->where_clause != NULL) {
inprint("Search Conditions:", num_indent+1); inprint("Search Conditions:", num_indent+1);
printExpression(stmt->where_clause, num_indent+2); printExpression(stmt->where_clause, num_indent+2);
} }
if (stmt->union_select != NULL) { if (stmt->union_select != NULL) {
inprint("Union:", num_indent+1); inprint("Union:", num_indent+1);
printSelectStatementInfo(stmt->union_select, num_indent+2); printSelectStatementInfo(stmt->union_select, num_indent+2);
} }
if (stmt->order != NULL) { if (stmt->order != NULL) {
inprint("OrderBy:", num_indent+1); inprint("OrderBy:", num_indent+1);
printExpression(stmt->order->expr, num_indent+2); printExpression(stmt->order->expr, num_indent+2);
if (stmt->order->type == kOrderAsc) inprint("ascending", num_indent+2); if (stmt->order->type == kOrderAsc) inprint("ascending", num_indent+2);
else inprint("descending", num_indent+2); else inprint("descending", num_indent+2);
} }
if (stmt->limit != NULL) { if (stmt->limit != NULL) {
inprint("Limit:", num_indent+1); inprint("Limit:", num_indent+1);
inprint(stmt->limit->limit, num_indent+2); inprint(stmt->limit->limit, num_indent+2);
} }
} }
void printImportStatementInfo(ImportStatement* stmt, uint num_indent) { void printImportStatementInfo(ImportStatement* stmt, uint num_indent) {
inprint("ImportStatment", num_indent); inprint("ImportStatment", num_indent);
inprint(stmt->file_path, num_indent+1); inprint(stmt->file_path, num_indent+1);
inprint(stmt->table_name, num_indent+1); inprint(stmt->table_name, num_indent+1);
} }
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent) { void printCreateStatementInfo(CreateStatement* stmt, uint num_indent) {
inprint("CreateStatment", num_indent); inprint("CreateStatment", num_indent);
inprint(stmt->table_name, num_indent+1); inprint(stmt->table_name, num_indent+1);
inprint(stmt->file_path, num_indent+1); inprint(stmt->file_path, num_indent+1);
} }
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent) { void printInsertStatementInfo(InsertStatement* stmt, uint num_indent) {
inprint("InsertStatment", num_indent); inprint("InsertStatment", num_indent);
inprint(stmt->table_name, num_indent+1); inprint(stmt->table_name, num_indent+1);
if (stmt->columns != NULL) { if (stmt->columns != NULL) {
inprint("Columns", num_indent+1); inprint("Columns", num_indent+1);
for (char* col_name : *stmt->columns) { for (char* col_name : *stmt->columns) {
inprint(col_name, num_indent+2); inprint(col_name, num_indent+2);
} }
} }
switch (stmt->type) { switch (stmt->type) {
case InsertStatement::kInsertValues: case InsertStatement::kInsertValues:
inprint("Values", num_indent+1); inprint("Values", num_indent+1);
for (Expr* expr : *stmt->values) { for (Expr* expr : *stmt->values) {
printExpression(expr, num_indent+2); printExpression(expr, num_indent+2);
} }
break; break;
case InsertStatement::kInsertSelect: case InsertStatement::kInsertSelect:
printSelectStatementInfo(stmt->select, num_indent+1); printSelectStatementInfo(stmt->select, num_indent+1);
break; break;
} }
} }
void printStatementInfo(SQLStatement* stmt) { void printStatementInfo(SQLStatement* stmt) {
switch (stmt->type()) { switch (stmt->type()) {
case kStmtSelect: case kStmtSelect:
printSelectStatementInfo((SelectStatement*) stmt, 0); printSelectStatementInfo((SelectStatement*) stmt, 0);
break; break;
case kStmtInsert: case kStmtInsert:
printInsertStatementInfo((InsertStatement*) stmt, 0); printInsertStatementInfo((InsertStatement*) stmt, 0);
break; break;
case kStmtCreate: case kStmtCreate:
printCreateStatementInfo((CreateStatement*) stmt, 0); printCreateStatementInfo((CreateStatement*) stmt, 0);
break; break;
case kStmtImport: case kStmtImport:
printImportStatementInfo((ImportStatement*) stmt, 0); printImportStatementInfo((ImportStatement*) stmt, 0);
break; break;
default: default:
break; break;
} }
} }
} // namespace hsql } // namespace hsql

View File

@ -5,12 +5,12 @@
namespace hsql { namespace hsql {
void printStatementInfo(SQLStatement* stmt); void printStatementInfo(SQLStatement* stmt);
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent); void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
void printImportStatementInfo(ImportStatement* stmt, uint num_indent); void printImportStatementInfo(ImportStatement* stmt, uint num_indent);
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent); void printInsertStatementInfo(InsertStatement* stmt, uint num_indent);
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent); void printCreateStatementInfo(CreateStatement* stmt, uint num_indent);
void printExpression(Expr* expr, uint num_indent); void printExpression(Expr* expr, uint num_indent);
} // namespace hsql } // namespace hsql

View File

@ -7,40 +7,40 @@
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, stmt);
ASSERT_NULL(stmt->where_clause); ASSERT_NULL(stmt->where_clause);
ASSERT_NULL(stmt->group_by); ASSERT_NULL(stmt->group_by);
} }
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, stmt);
ASSERT_FALSE(stmt->select_distinct); ASSERT_FALSE(stmt->select_distinct);
GroupByDescription* group = stmt->group_by; GroupByDescription* group = stmt->group_by;
ASSERT_NOTNULL(group); ASSERT_NOTNULL(group);
ASSERT_EQ(group->columns->size(), 1); ASSERT_EQ(group->columns->size(), 1);
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));
} }
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, stmt);
ASSERT(stmt->select_distinct); ASSERT(stmt->select_distinct);
ASSERT_NULL(stmt->where_clause); ASSERT_NULL(stmt->where_clause);
} }
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, stmt);
ASSERT_FALSE(stmt->select_distinct); ASSERT_FALSE(stmt->select_distinct);
ASSERT_EQ(stmt->select_list->size(), 3); ASSERT_EQ(stmt->select_list->size(), 3);
ASSERT(!stmt->select_list->at(1)->distinct); ASSERT(!stmt->select_list->at(1)->distinct);
ASSERT(stmt->select_list->at(2)->distinct); ASSERT(stmt->select_list->at(2)->distinct);
} }

View File

@ -3,53 +3,53 @@
class TestsManager { class TestsManager {
// Note: static initialization fiasco // Note: static initialization fiasco
// http://www.parashift.com/c++-faq-lite/static-init-order.html // http://www.parashift.com/c++-faq-lite/static-init-order.html
// 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>& test_names() { static std::vector<std::string>& test_names() {
static std::vector<std::string>* test_names = new std::vector<std::string>; static std::vector<std::string>* test_names = new std::vector<std::string>;
return *test_names; return *test_names;
} }
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 = new std::vector<void (*)(void)>;
return *tests; return *tests;
} }
}; };
int AddTest(void (*foo)(void), std::string name) { int AddTest(void (*foo)(void), std::string name) {
TestsManager::tests().push_back(foo); TestsManager::tests().push_back(foo);
TestsManager::test_names().push_back(name); TestsManager::test_names().push_back(name);
return 0; return 0;
} }
void RunTests() { void RunTests() {
size_t num_failed = 0; size_t num_failed = 0;
for (size_t i = 0; i < TestsManager::tests().size(); ++i) { for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::test_names()[i].c_str()); printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::test_names()[i].c_str());
try { try {
// Run test // Run test
(*TestsManager::tests()[i])(); (*TestsManager::tests()[i])();
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::test_names()[i].c_str()); printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::test_names()[i].c_str());
} catch (AssertionFailedException& e) { } catch (AssertionFailedException& e) {
printf("\033[1;31m{ failed} %s\n", TestsManager::test_names()[i].c_str()); printf("\033[1;31m{ failed} %s\n", TestsManager::test_names()[i].c_str());
printf("\tAssertion failed: %s\n\033[0m", e.what()); printf("\tAssertion failed: %s\n\033[0m", e.what());
num_failed++; num_failed++;
} }
} }
} }
int main() { int main() {
RunTests(); RunTests();
return 0; return 0;
} }

View File

@ -32,16 +32,16 @@
class AssertionFailedException: public std::exception { class AssertionFailedException: public std::exception {
public: public:
AssertionFailedException(std::string msg) : AssertionFailedException(std::string msg) :
std::exception(), std::exception(),
_msg(msg) {}; _msg(msg) {};
virtual const char* what() const throw() { virtual const char* what() const throw() {
return _msg.c_str(); return _msg.c_str();
} }
protected: protected:
std::string _msg; std::string _msg;
}; };