Merge pull request #23 from torpedro/statements-clean
Clean-Up and Reformatting of Code
This commit is contained in:
commit
89a81848b4
|
@ -1,8 +1,10 @@
|
|||
|
||||
--style=google
|
||||
|
||||
# indentation
|
||||
--indent=spaces=4
|
||||
--indent=spaces=2
|
||||
--indent-namespaces
|
||||
|
||||
--style=java
|
||||
--style=attach
|
||||
-A2
|
||||
--align-reference=type
|
||||
--align-pointer=type
|
||||
--pad-oper
|
||||
|
|
|
@ -12,22 +12,22 @@ namespace hsql {
|
|||
fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n");
|
||||
}
|
||||
|
||||
|
||||
SQLParserResult* SQLParser::parseSQLString(const char* text) {
|
||||
SQLParserResult* result = NULL;
|
||||
yyscan_t scanner;
|
||||
YY_BUFFER_STATE state;
|
||||
|
||||
if (hsql_lex_init(&scanner)) {
|
||||
// couldn't initialize
|
||||
// Couldn't initialize the lexer.
|
||||
fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = hsql__scan_string(text, scanner);
|
||||
|
||||
// Parser and return early if it failed.
|
||||
if (hsql_parse(&result, scanner)) {
|
||||
// Returns an error stmt object
|
||||
// Returns an error stmt object.
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,18 @@
|
|||
#include "sql/statements.h"
|
||||
|
||||
namespace hsql {
|
||||
/**
|
||||
* Main class for parsing SQL strings
|
||||
*/
|
||||
|
||||
// Static methods used to parse SQL strings.
|
||||
class SQLParser {
|
||||
public:
|
||||
// Parses a given constant character SQL string.
|
||||
static SQLParserResult* parseSQLString(const char* sql);
|
||||
|
||||
// Parses an SQL std::string.
|
||||
static SQLParserResult* parseSQLString(const std::string& sql);
|
||||
|
||||
private:
|
||||
// Static class can't be instatiated.
|
||||
SQLParser();
|
||||
};
|
||||
|
||||
|
|
|
@ -4,38 +4,63 @@
|
|||
namespace hsql {
|
||||
|
||||
SQLParserResult::SQLParserResult() :
|
||||
isValid(true),
|
||||
errorMsg(NULL) {};
|
||||
|
||||
isValid_(true),
|
||||
errorMsg_(NULL) {};
|
||||
|
||||
SQLParserResult::SQLParserResult(SQLStatement* stmt) :
|
||||
isValid(true),
|
||||
errorMsg(NULL) {
|
||||
isValid_(true),
|
||||
errorMsg_(NULL) {
|
||||
addStatement(stmt);
|
||||
};
|
||||
|
||||
|
||||
SQLParserResult::~SQLParserResult() {
|
||||
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
|
||||
delete *it;
|
||||
for (SQLStatement* statement : statements_) {
|
||||
delete statement;
|
||||
}
|
||||
|
||||
delete errorMsg;
|
||||
delete errorMsg_;
|
||||
}
|
||||
|
||||
|
||||
void SQLParserResult::addStatement(SQLStatement* stmt) {
|
||||
statements.push_back(stmt);
|
||||
statements_.push_back(stmt);
|
||||
}
|
||||
|
||||
|
||||
SQLStatement* SQLParserResult::getStatement(int id) {
|
||||
return statements[id];
|
||||
const SQLStatement* SQLParserResult::getStatement(int index) const {
|
||||
return statements_[index];
|
||||
}
|
||||
|
||||
SQLStatement* SQLParserResult::getMutableStatement(int index) {
|
||||
return statements_[index];
|
||||
}
|
||||
|
||||
size_t SQLParserResult::size() {
|
||||
return statements.size();
|
||||
size_t SQLParserResult::size() const {
|
||||
return statements_.size();
|
||||
}
|
||||
|
||||
bool SQLParserResult::isValid() const {
|
||||
return isValid_;
|
||||
}
|
||||
|
||||
const char* SQLParserResult::errorMsg() const {
|
||||
return errorMsg_;
|
||||
}
|
||||
|
||||
int SQLParserResult::errorLine() const {
|
||||
return errorLine_;
|
||||
}
|
||||
|
||||
int SQLParserResult::errorColumn() const {
|
||||
return errorColumn_;
|
||||
}
|
||||
|
||||
void SQLParserResult::setIsValid(bool isValid) {
|
||||
isValid_ = isValid;
|
||||
}
|
||||
|
||||
void SQLParserResult::setErrorDetails(const char* errorMsg, int errorLine, int errorColumn) {
|
||||
errorMsg_ = errorMsg;
|
||||
errorLine_ = errorLine;
|
||||
errorColumn_ = errorColumn;
|
||||
}
|
||||
|
||||
} // namespace hsql
|
|
@ -4,30 +4,67 @@
|
|||
#include "sql/SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
/**
|
||||
* Represents the result of the SQLParser.
|
||||
* If parsing was successful it contains a list of SQLStatement.
|
||||
*/
|
||||
// Represents the result of the SQLParser.
|
||||
// If parsing was successful it contains a list of SQLStatement.
|
||||
class SQLParserResult {
|
||||
public:
|
||||
|
||||
// Initialize with empty statement list.
|
||||
SQLParserResult();
|
||||
|
||||
// Initialize with a single statement.
|
||||
// Takes ownership of the statement.
|
||||
SQLParserResult(SQLStatement* stmt);
|
||||
|
||||
// Deletes all statements in the resul.
|
||||
virtual ~SQLParserResult();
|
||||
|
||||
// Returns true if parsing was successful.
|
||||
bool isValid() const;
|
||||
|
||||
// Returns the number of statements in the result.
|
||||
size_t size() const;
|
||||
|
||||
// Returns the error message, if an error occurred.
|
||||
const char* errorMsg() const;
|
||||
|
||||
// Returns the line number of the occurrance of the error in the query.
|
||||
int errorLine() const;
|
||||
|
||||
// Returns the column number of the occurrance of the error in the query.
|
||||
int errorColumn() const;
|
||||
|
||||
// Gets the SQL statement with the given index.
|
||||
const SQLStatement* getStatement(int index) const;
|
||||
|
||||
// Gets the non const SQL statement with the given index.
|
||||
SQLStatement* getMutableStatement(int index);
|
||||
|
||||
// Adds a statement to the result list of statements.
|
||||
// Takes ownership of the statement.
|
||||
void addStatement(SQLStatement* stmt);
|
||||
|
||||
SQLStatement* getStatement(int id);
|
||||
// Set whether parsing was successful.
|
||||
void setIsValid(bool isValid);
|
||||
|
||||
size_t size();
|
||||
// Set the details of the error, if available.
|
||||
void setErrorDetails(const char* errorMsg, int errorLine, int errorColumn);
|
||||
|
||||
// public properties
|
||||
std::vector<SQLStatement*> statements;
|
||||
bool isValid;
|
||||
|
||||
const char* errorMsg;
|
||||
int errorLine;
|
||||
int errorColumn;
|
||||
private:
|
||||
// List of statements within the result.
|
||||
std::vector<SQLStatement*> statements_;
|
||||
|
||||
// Flag indicating the parsing was successful.
|
||||
bool isValid_;
|
||||
|
||||
// Error message, if an error occurred.
|
||||
const char* errorMsg_;
|
||||
|
||||
// Line number of the occurrance of the error in the query.
|
||||
int errorLine_;
|
||||
|
||||
// Column number of the occurrance of the error in the query.
|
||||
int errorColumn_;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -48,7 +48,7 @@
|
|||
extern int hsql_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
#line 42 "bison_parser.y" /* yacc.c:1909 */
|
||||
#line 40 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
// %code requires block
|
||||
|
||||
|
@ -209,7 +209,7 @@ extern int hsql_debug;
|
|||
typedef union HSQL_STYPE HSQL_STYPE;
|
||||
union HSQL_STYPE
|
||||
{
|
||||
#line 101 "bison_parser.y" /* yacc.c:1909 */
|
||||
#line 99 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
double fval;
|
||||
int64_t ival;
|
||||
|
|
|
@ -21,10 +21,8 @@ using namespace hsql;
|
|||
int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const char *msg) {
|
||||
|
||||
SQLParserResult* list = new SQLParserResult();
|
||||
list->isValid = false;
|
||||
list->errorMsg = strdup(msg);
|
||||
list->errorLine = llocp->first_line;
|
||||
list->errorColumn = llocp->first_column;
|
||||
list->setIsValid(false);
|
||||
list->setErrorDetails(strdup(msg), llocp->first_line, llocp->first_column);
|
||||
|
||||
*result = list;
|
||||
return 0;
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
/**
|
||||
* Represents definition of a table column
|
||||
*/
|
||||
// Represents definition of a table column
|
||||
struct ColumnDefinition {
|
||||
enum DataType {
|
||||
TEXT,
|
||||
|
@ -14,48 +13,30 @@ namespace hsql {
|
|||
DOUBLE
|
||||
};
|
||||
|
||||
ColumnDefinition(char* name, DataType type) :
|
||||
name(name),
|
||||
type(type) {}
|
||||
|
||||
virtual ~ColumnDefinition() {
|
||||
delete name;
|
||||
}
|
||||
ColumnDefinition(char* name, DataType type);
|
||||
virtual ~ColumnDefinition();
|
||||
|
||||
char* name;
|
||||
DataType type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents SQL Create statements.
|
||||
* Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||
*/
|
||||
|
||||
// Represents SQL Create statements.
|
||||
// Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||
struct CreateStatement : SQLStatement {
|
||||
enum CreateType {
|
||||
kTable,
|
||||
kTableFromTbl // Hyrise file format
|
||||
};
|
||||
|
||||
CreateStatement(CreateType type) :
|
||||
SQLStatement(kStmtCreate),
|
||||
type(type),
|
||||
ifNotExists(false),
|
||||
filePath(NULL),
|
||||
tableName(NULL),
|
||||
columns(NULL) {};
|
||||
|
||||
virtual ~CreateStatement() {
|
||||
delete columns;
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
CreateStatement(CreateType type);
|
||||
virtual ~CreateStatement();
|
||||
|
||||
CreateType type;
|
||||
|
||||
bool ifNotExists;
|
||||
const char* filePath;
|
||||
const char* tableName;
|
||||
std::vector<ColumnDefinition*>* columns;
|
||||
bool ifNotExists; // default: false
|
||||
const char* filePath; // default: NULL
|
||||
const char* tableName; // default: NULL
|
||||
std::vector<ColumnDefinition*>* columns; // default: NULL
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
|
|
@ -3,23 +3,14 @@
|
|||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
/**
|
||||
* Represents SQL Delete statements.
|
||||
* Example: "DELETE FROM students WHERE grade > 3.0"
|
||||
*
|
||||
* Note: if (expr == NULL) => delete all rows (truncate)
|
||||
*/
|
||||
// Represents SQL Delete statements.
|
||||
// Example: "DELETE FROM students WHERE grade > 3.0"
|
||||
// Note: if (expr == NULL) => delete all rows (truncate)
|
||||
struct DeleteStatement : SQLStatement {
|
||||
DeleteStatement() :
|
||||
SQLStatement(kStmtDelete),
|
||||
tableName(NULL),
|
||||
expr(NULL) {};
|
||||
|
||||
virtual ~DeleteStatement() {
|
||||
delete tableName;
|
||||
delete expr;
|
||||
}
|
||||
DeleteStatement();
|
||||
virtual ~DeleteStatement();
|
||||
|
||||
char* tableName;
|
||||
Expr* expr;
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
/**
|
||||
* Represents SQL Delete statements.
|
||||
* Example "DROP TABLE students;"
|
||||
*/
|
||||
// Represents SQL Delete statements.
|
||||
// Example "DROP TABLE students;"
|
||||
struct DropStatement : SQLStatement {
|
||||
enum EntityType {
|
||||
kTable,
|
||||
|
@ -17,14 +16,8 @@ namespace hsql {
|
|||
kPreparedStatement
|
||||
};
|
||||
|
||||
DropStatement(EntityType type) :
|
||||
SQLStatement(kStmtDrop),
|
||||
type(type),
|
||||
name(NULL) {}
|
||||
|
||||
virtual ~DropStatement() {
|
||||
delete name;
|
||||
}
|
||||
DropStatement(EntityType type);
|
||||
virtual ~DropStatement();
|
||||
|
||||
EntityType type;
|
||||
const char* name;
|
||||
|
|
|
@ -9,15 +9,8 @@ namespace hsql {
|
|||
* Example: "EXECUTE ins_prep(100, "test", 2.3);"
|
||||
*/
|
||||
struct ExecuteStatement : SQLStatement {
|
||||
ExecuteStatement() :
|
||||
SQLStatement(kStmtExecute),
|
||||
name(NULL),
|
||||
parameters(NULL) {}
|
||||
|
||||
virtual ~ExecuteStatement() {
|
||||
delete name;
|
||||
delete parameters;
|
||||
}
|
||||
ExecuteStatement();
|
||||
virtual ~ExecuteStatement();
|
||||
|
||||
const char* name;
|
||||
std::vector<Expr*>* parameters;
|
||||
|
|
|
@ -5,31 +5,33 @@
|
|||
|
||||
namespace hsql {
|
||||
|
||||
char* substr(const char* source, int from, int to) {
|
||||
int len = to-from;
|
||||
char* copy = new char[len+1];
|
||||
strncpy(copy, source+from, len);
|
||||
copy[len] = '\0';
|
||||
return copy;
|
||||
Expr::Expr(ExprType type) :
|
||||
type(type),
|
||||
expr(NULL),
|
||||
expr2(NULL),
|
||||
name(NULL),
|
||||
table(NULL),
|
||||
alias(NULL) {};
|
||||
|
||||
Expr::~Expr() {
|
||||
delete expr;
|
||||
delete expr2;
|
||||
delete name;
|
||||
delete table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->op_type = op;
|
||||
e->opType = op;
|
||||
e->expr = expr;
|
||||
e->expr2 = NULL;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->op_type = op;
|
||||
e->op_char = 0;
|
||||
e->opType = op;
|
||||
e->opChar = 0;
|
||||
e->expr = expr1;
|
||||
e->expr2 = expr2;
|
||||
return e;
|
||||
|
@ -37,15 +39,13 @@ namespace hsql {
|
|||
|
||||
Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->op_type = SIMPLE_OP;
|
||||
e->op_char = op;
|
||||
e->opType = SIMPLE_OP;
|
||||
e->opChar = op;
|
||||
e->expr = expr1;
|
||||
e->expr2 = expr2;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Expr* Expr::makeLiteral(int64_t val) {
|
||||
Expr* e = new Expr(kExprLiteralInt);
|
||||
e->ival = val;
|
||||
|
@ -92,11 +92,40 @@ namespace hsql {
|
|||
return e;
|
||||
}
|
||||
|
||||
Expr::~Expr() {
|
||||
delete expr;
|
||||
delete expr2;
|
||||
delete name;
|
||||
delete table;
|
||||
bool Expr::isType(ExprType e_type) {
|
||||
return e_type == type;
|
||||
}
|
||||
|
||||
bool Expr::isLiteral() {
|
||||
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
|
||||
}
|
||||
|
||||
bool Expr::hasAlias() {
|
||||
return alias != NULL;
|
||||
}
|
||||
|
||||
bool Expr::hasTable() {
|
||||
return table != NULL;
|
||||
}
|
||||
|
||||
char* Expr::getName() {
|
||||
if (alias != NULL) return alias;
|
||||
else return name;
|
||||
}
|
||||
|
||||
bool Expr::isSimpleOp() {
|
||||
return opType == SIMPLE_OP;
|
||||
}
|
||||
|
||||
bool Expr::isSimpleOp(char op) {
|
||||
return isSimpleOp() && opChar == op;
|
||||
}
|
||||
|
||||
char* substr(const char* source, int from, int to) {
|
||||
int len = to - from;
|
||||
char* copy = new char[len + 1];
|
||||
strncpy(copy, source + from, len);
|
||||
copy[len] = '\0';
|
||||
return copy;
|
||||
}
|
||||
} // namespace hsql
|
103
src/sql/Expr.h
103
src/sql/Expr.h
|
@ -6,12 +6,11 @@
|
|||
|
||||
namespace hsql {
|
||||
|
||||
// Helper function
|
||||
// Helper function used by the lexer.
|
||||
// TODO: move to more appropriate place.
|
||||
char* substr(const char* source, int from, int to);
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
enum ExprType {
|
||||
kExprLiteralFloat,
|
||||
kExprLiteralString,
|
||||
kExprLiteralInt,
|
||||
|
@ -20,27 +19,21 @@ namespace hsql {
|
|||
kExprColumnRef,
|
||||
kExprFunctionRef,
|
||||
kExprOperator
|
||||
} ExprType;
|
||||
|
||||
};
|
||||
|
||||
typedef struct Expr Expr;
|
||||
|
||||
/**
|
||||
* Represents SQL expressions (i.e. literals, operators, column_refs)
|
||||
*
|
||||
* TODO: When destructing a placeholder expression, we might need to alter the placeholder_list
|
||||
*/
|
||||
// Represents SQL expressions (i.e. literals, operators, column_refs).
|
||||
// TODO: When destructing a placeholder expression, we might need to alter the placeholder_list.
|
||||
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
|
||||
*/
|
||||
typedef enum {
|
||||
// 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 {
|
||||
SIMPLE_OP,
|
||||
// Binary
|
||||
|
||||
// Binary operators.
|
||||
NOT_EQUALS,
|
||||
LESS_EQ,
|
||||
GREATER_EQ,
|
||||
|
@ -48,24 +41,20 @@ namespace hsql {
|
|||
NOT_LIKE,
|
||||
AND,
|
||||
OR,
|
||||
// Unary
|
||||
|
||||
// Unary operators.
|
||||
NOT,
|
||||
UMINUS,
|
||||
ISNULL
|
||||
} OperatorType;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Expr(ExprType type) :
|
||||
type(type),
|
||||
expr(NULL),
|
||||
expr2(NULL),
|
||||
name(NULL),
|
||||
table(NULL),
|
||||
alias(NULL) {};
|
||||
Expr(ExprType type);
|
||||
|
||||
// Interesting side-effect:
|
||||
// Making the destructor virtual used to cause segmentation faults
|
||||
// Making the destructor virtual used to cause segmentation faults.
|
||||
// TODO: inspect.
|
||||
~Expr();
|
||||
|
||||
ExprType type;
|
||||
|
@ -79,51 +68,45 @@ namespace hsql {
|
|||
int64_t ival;
|
||||
int64_t ival2;
|
||||
|
||||
OperatorType op_type;
|
||||
char op_char;
|
||||
OperatorType opType;
|
||||
char opChar;
|
||||
bool distinct;
|
||||
|
||||
// Convenience accessor methods.
|
||||
|
||||
/**
|
||||
* Convenience accessor methods
|
||||
*/
|
||||
inline bool isType(ExprType e_type) {
|
||||
return e_type == type;
|
||||
}
|
||||
inline bool isLiteral() {
|
||||
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
|
||||
}
|
||||
inline bool hasAlias() {
|
||||
return alias != NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
bool isType(ExprType e_type);
|
||||
|
||||
bool isLiteral();
|
||||
|
||||
bool hasAlias();
|
||||
|
||||
bool hasTable();
|
||||
|
||||
char* getName();
|
||||
|
||||
bool isSimpleOp();
|
||||
|
||||
bool isSimpleOp(char op);
|
||||
|
||||
|
||||
/**
|
||||
* Static expression constructors
|
||||
*/
|
||||
// Static constructors.
|
||||
|
||||
static Expr* makeOpUnary(OperatorType op, Expr* expr);
|
||||
|
||||
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);
|
||||
|
||||
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
||||
|
||||
static Expr* makeLiteral(int64_t val);
|
||||
|
||||
static Expr* makeLiteral(double val);
|
||||
|
||||
static Expr* makeLiteral(char* val);
|
||||
|
||||
static Expr* makeColumnRef(char* name);
|
||||
|
||||
static Expr* makeColumnRef(char* table, char* name);
|
||||
|
||||
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
|
||||
|
||||
static Expr* makePlaceholder(int id);
|
||||
|
|
|
@ -13,16 +13,8 @@ namespace hsql {
|
|||
kImportTbl, // Hyrise file format
|
||||
};
|
||||
|
||||
ImportStatement(ImportType type) :
|
||||
SQLStatement(kStmtImport),
|
||||
type(type),
|
||||
filePath(NULL),
|
||||
tableName(NULL) {};
|
||||
|
||||
virtual ~ImportStatement() {
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
ImportStatement(ImportType type);
|
||||
virtual ~ImportStatement();
|
||||
|
||||
ImportType type;
|
||||
const char* filePath;
|
||||
|
|
|
@ -15,20 +15,8 @@ namespace hsql {
|
|||
kInsertSelect
|
||||
};
|
||||
|
||||
InsertStatement(InsertType type) :
|
||||
SQLStatement(kStmtInsert),
|
||||
type(type),
|
||||
tableName(NULL),
|
||||
columns(NULL),
|
||||
values(NULL),
|
||||
select(NULL) {}
|
||||
|
||||
virtual ~InsertStatement() {
|
||||
delete tableName;
|
||||
delete columns;
|
||||
delete values;
|
||||
delete select;
|
||||
}
|
||||
InsertStatement(InsertType type);
|
||||
virtual ~InsertStatement();
|
||||
|
||||
InsertType type;
|
||||
const char* tableName;
|
||||
|
|
|
@ -12,15 +12,8 @@ namespace hsql {
|
|||
* Example: "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
|
||||
*/
|
||||
struct PrepareStatement : SQLStatement {
|
||||
PrepareStatement() :
|
||||
SQLStatement(kStmtPrepare),
|
||||
name(NULL),
|
||||
query(NULL) {}
|
||||
|
||||
virtual ~PrepareStatement() {
|
||||
delete query;
|
||||
delete name;
|
||||
}
|
||||
PrepareStatement();
|
||||
virtual ~PrepareStatement();
|
||||
|
||||
/**
|
||||
* When setting the placeholders we need to make sure that they are in the correct order.
|
||||
|
@ -28,17 +21,7 @@ namespace hsql {
|
|||
*
|
||||
* @param vector of placeholders that the parser found
|
||||
*/
|
||||
void setPlaceholders(std::vector<void*> ph) {
|
||||
for (void* e : ph) {
|
||||
if (e != NULL)
|
||||
placeholders.push_back((Expr*) e);
|
||||
}
|
||||
// Sort by col-id
|
||||
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
||||
|
||||
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||
}
|
||||
void setPlaceholders(std::vector<void*> ph);
|
||||
|
||||
const char* name;
|
||||
SQLParserResult* query;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <vector>
|
||||
|
||||
namespace hsql {
|
||||
typedef enum {
|
||||
enum StatementType {
|
||||
kStmtError, // unused
|
||||
kStmtSelect,
|
||||
kStmtImport,
|
||||
|
@ -19,23 +19,20 @@ namespace hsql {
|
|||
kStmtExport,
|
||||
kStmtRename,
|
||||
kStmtAlter
|
||||
} StatementType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base struct for every SQL statement
|
||||
*/
|
||||
struct SQLStatement {
|
||||
SQLStatement(StatementType type) :
|
||||
_type(type) {};
|
||||
SQLStatement(StatementType type);
|
||||
|
||||
virtual ~SQLStatement() {}
|
||||
virtual ~SQLStatement();
|
||||
|
||||
virtual StatementType type() {
|
||||
return _type;
|
||||
}
|
||||
virtual StatementType type() const;
|
||||
|
||||
private:
|
||||
StatementType _type;
|
||||
StatementType type_;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
|
|
@ -6,23 +6,18 @@
|
|||
#include "Table.h"
|
||||
|
||||
namespace hsql {
|
||||
typedef enum {
|
||||
enum OrderType {
|
||||
kOrderAsc,
|
||||
kOrderDesc
|
||||
} OrderType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Description of the order by clause within a select statement
|
||||
* TODO: hold multiple expressions to be sorted by
|
||||
*/
|
||||
struct OrderDescription {
|
||||
OrderDescription(OrderType type, Expr* expr) :
|
||||
type(type),
|
||||
expr(expr) {}
|
||||
|
||||
virtual ~OrderDescription() {
|
||||
delete expr;
|
||||
}
|
||||
OrderDescription(OrderType type, Expr* expr);
|
||||
virtual ~OrderDescription();
|
||||
|
||||
OrderType type;
|
||||
Expr* expr;
|
||||
|
@ -35,9 +30,7 @@ namespace hsql {
|
|||
* Description of the limit clause within a select statement
|
||||
*/
|
||||
struct LimitDescription {
|
||||
LimitDescription(int64_t limit, int64_t offset) :
|
||||
limit(limit),
|
||||
offset(offset) {}
|
||||
LimitDescription(int64_t limit, int64_t offset);
|
||||
|
||||
int64_t limit;
|
||||
int64_t offset;
|
||||
|
@ -47,14 +40,9 @@ namespace hsql {
|
|||
* Description of the group-by clause within a select statement
|
||||
*/
|
||||
struct GroupByDescription {
|
||||
GroupByDescription() :
|
||||
columns(NULL),
|
||||
having(NULL) {}
|
||||
|
||||
~GroupByDescription() {
|
||||
delete columns;
|
||||
delete having;
|
||||
}
|
||||
GroupByDescription();
|
||||
// TODO: make virtual
|
||||
~GroupByDescription();
|
||||
|
||||
std::vector<Expr*>* columns;
|
||||
Expr* having;
|
||||
|
@ -65,25 +53,8 @@ namespace hsql {
|
|||
* TODO: add union_order and union_limit
|
||||
*/
|
||||
struct SelectStatement : SQLStatement {
|
||||
SelectStatement() :
|
||||
SQLStatement(kStmtSelect),
|
||||
fromTable(NULL),
|
||||
selectDistinct(false),
|
||||
selectList(NULL),
|
||||
whereClause(NULL),
|
||||
groupBy(NULL),
|
||||
unionSelect(NULL),
|
||||
order(NULL),
|
||||
limit(NULL) {};
|
||||
|
||||
virtual ~SelectStatement() {
|
||||
delete fromTable;
|
||||
delete selectList;
|
||||
delete whereClause;
|
||||
delete groupBy;
|
||||
delete order;
|
||||
delete limit;
|
||||
}
|
||||
SelectStatement();
|
||||
virtual ~SelectStatement();
|
||||
|
||||
TableRef* fromTable;
|
||||
bool selectDistinct;
|
||||
|
|
|
@ -11,33 +11,17 @@ namespace hsql {
|
|||
struct JoinDefinition;
|
||||
struct TableRef;
|
||||
|
||||
|
||||
/**
|
||||
* @enum TableRefType
|
||||
* Types table references
|
||||
*/
|
||||
typedef enum {
|
||||
// Possible table reference types.
|
||||
enum TableRefType {
|
||||
kTableName,
|
||||
kTableSelect,
|
||||
kTableJoin,
|
||||
kTableCrossProduct
|
||||
} TableRefType;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @struct TableRef
|
||||
* @brief Holds reference to tables. Can be either table names or a select statement.
|
||||
*/
|
||||
// Holds reference to tables. Can be either table names or a select statement.
|
||||
struct TableRef {
|
||||
TableRef(TableRefType type) :
|
||||
type(type),
|
||||
schema(NULL),
|
||||
name(NULL),
|
||||
alias(NULL),
|
||||
select(NULL),
|
||||
list(NULL),
|
||||
join(NULL) {}
|
||||
|
||||
TableRef(TableRefType type);
|
||||
virtual ~TableRef();
|
||||
|
||||
TableRefType type;
|
||||
|
@ -50,49 +34,25 @@ namespace hsql {
|
|||
std::vector<TableRef*>* list;
|
||||
JoinDefinition* join;
|
||||
|
||||
// Returns true if a schema is set.
|
||||
bool hasSchema();
|
||||
|
||||
/**
|
||||
* Convenience accessor methods
|
||||
*/
|
||||
inline bool hasSchema() {
|
||||
return schema != NULL;
|
||||
}
|
||||
|
||||
inline char* getName() {
|
||||
if (alias != NULL) return alias;
|
||||
else return name;
|
||||
}
|
||||
// Returns the alias, if it is set. Otherwise the name.
|
||||
char* getName();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum JoinType
|
||||
* Types of joins
|
||||
*/
|
||||
typedef enum {
|
||||
// Possible types of joins.
|
||||
enum JoinType {
|
||||
kJoinInner,
|
||||
kJoinOuter,
|
||||
kJoinLeft,
|
||||
kJoinRight,
|
||||
} JoinType;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @struct JoinDefinition
|
||||
* @brief Definition of a join table
|
||||
*/
|
||||
// Definition of a join construct.
|
||||
struct JoinDefinition {
|
||||
JoinDefinition() :
|
||||
left(NULL),
|
||||
right(NULL),
|
||||
condition(NULL),
|
||||
type(kJoinInner) {}
|
||||
|
||||
virtual ~JoinDefinition() {
|
||||
delete left;
|
||||
delete right;
|
||||
delete condition;
|
||||
}
|
||||
JoinDefinition();
|
||||
virtual ~JoinDefinition();
|
||||
|
||||
TableRef* left;
|
||||
TableRef* right;
|
||||
|
@ -101,7 +61,5 @@ namespace hsql {
|
|||
JoinType type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
||||
|
|
|
@ -16,17 +16,8 @@ namespace hsql {
|
|||
* Represents SQL Update statements.
|
||||
*/
|
||||
struct UpdateStatement : SQLStatement {
|
||||
UpdateStatement() :
|
||||
SQLStatement(kStmtUpdate),
|
||||
table(NULL),
|
||||
updates(NULL),
|
||||
where(NULL) {}
|
||||
|
||||
virtual ~UpdateStatement() {
|
||||
delete table;
|
||||
delete updates;
|
||||
delete where;
|
||||
}
|
||||
UpdateStatement();
|
||||
virtual ~UpdateStatement();
|
||||
|
||||
// TODO: switch to char* instead of TableRef
|
||||
TableRef* table;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#include "Table.h"
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
||||
TableRef::~TableRef() {
|
||||
delete name;
|
||||
delete alias;
|
||||
delete select;
|
||||
delete list;
|
||||
}
|
||||
|
||||
|
||||
} // namespace hsql
|
|
@ -0,0 +1,222 @@
|
|||
|
||||
#include "statements.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// SQLStatement
|
||||
SQLStatement::SQLStatement(StatementType type) :
|
||||
type_(type) {};
|
||||
|
||||
SQLStatement::~SQLStatement() {}
|
||||
|
||||
StatementType SQLStatement::type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
// ColumnDefinition
|
||||
ColumnDefinition::ColumnDefinition(char* name, DataType type) :
|
||||
name(name),
|
||||
type(type) {};
|
||||
|
||||
ColumnDefinition::~ColumnDefinition() {
|
||||
delete name;
|
||||
}
|
||||
|
||||
// CreateStatemnet
|
||||
CreateStatement::CreateStatement(CreateType type) :
|
||||
SQLStatement(kStmtCreate),
|
||||
type(type),
|
||||
ifNotExists(false),
|
||||
filePath(NULL),
|
||||
tableName(NULL),
|
||||
columns(NULL) {};
|
||||
|
||||
CreateStatement::~CreateStatement() {
|
||||
delete columns;
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
|
||||
// DeleteStatement
|
||||
DeleteStatement::DeleteStatement() :
|
||||
SQLStatement(kStmtDelete),
|
||||
tableName(NULL),
|
||||
expr(NULL) {};
|
||||
|
||||
DeleteStatement::~DeleteStatement() {
|
||||
delete tableName;
|
||||
delete expr;
|
||||
}
|
||||
|
||||
// DropStatament
|
||||
DropStatement::DropStatement(EntityType type) :
|
||||
SQLStatement(kStmtDrop),
|
||||
type(type),
|
||||
name(NULL) {}
|
||||
|
||||
DropStatement::~DropStatement() {
|
||||
delete name;
|
||||
}
|
||||
|
||||
// ExecuteStatement
|
||||
ExecuteStatement::ExecuteStatement() :
|
||||
SQLStatement(kStmtExecute),
|
||||
name(NULL),
|
||||
parameters(NULL) {}
|
||||
|
||||
ExecuteStatement::~ExecuteStatement() {
|
||||
delete name;
|
||||
delete parameters;
|
||||
}
|
||||
|
||||
// ImportStatement
|
||||
ImportStatement::ImportStatement(ImportType type) :
|
||||
SQLStatement(kStmtImport),
|
||||
type(type),
|
||||
filePath(NULL),
|
||||
tableName(NULL) {};
|
||||
|
||||
ImportStatement::~ImportStatement() {
|
||||
delete filePath;
|
||||
delete tableName;
|
||||
}
|
||||
|
||||
// InsertStatement
|
||||
InsertStatement::InsertStatement(InsertType type) :
|
||||
SQLStatement(kStmtInsert),
|
||||
type(type),
|
||||
tableName(NULL),
|
||||
columns(NULL),
|
||||
values(NULL),
|
||||
select(NULL) {}
|
||||
|
||||
InsertStatement::~InsertStatement() {
|
||||
delete tableName;
|
||||
delete columns;
|
||||
delete values;
|
||||
delete select;
|
||||
}
|
||||
|
||||
// PrepareStatement
|
||||
PrepareStatement::PrepareStatement() :
|
||||
SQLStatement(kStmtPrepare),
|
||||
name(NULL),
|
||||
query(NULL) {}
|
||||
|
||||
PrepareStatement::~PrepareStatement() {
|
||||
delete query;
|
||||
delete name;
|
||||
}
|
||||
|
||||
void PrepareStatement::setPlaceholders(std::vector<void*> ph) {
|
||||
for (void* e : ph) {
|
||||
if (e != NULL)
|
||||
placeholders.push_back((Expr*) e);
|
||||
}
|
||||
// Sort by col-id
|
||||
std::sort(placeholders.begin(), placeholders.end(), [](Expr * i, Expr * j) -> bool { return (i->ival < j->ival); });
|
||||
|
||||
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||
}
|
||||
|
||||
// SelectStatement.h
|
||||
|
||||
// OrderDescription
|
||||
OrderDescription::OrderDescription(OrderType type, Expr* expr) :
|
||||
type(type),
|
||||
expr(expr) {}
|
||||
|
||||
OrderDescription::~OrderDescription() {
|
||||
delete expr;
|
||||
}
|
||||
|
||||
// LimitDescription
|
||||
LimitDescription::LimitDescription(int64_t limit, int64_t offset) :
|
||||
limit(limit),
|
||||
offset(offset) {}
|
||||
|
||||
// GroypByDescription
|
||||
GroupByDescription::GroupByDescription() :
|
||||
columns(NULL),
|
||||
having(NULL) {}
|
||||
|
||||
GroupByDescription::~GroupByDescription() {
|
||||
delete columns;
|
||||
delete having;
|
||||
}
|
||||
|
||||
// SelectStatement
|
||||
SelectStatement::SelectStatement() :
|
||||
SQLStatement(kStmtSelect),
|
||||
fromTable(NULL),
|
||||
selectDistinct(false),
|
||||
selectList(NULL),
|
||||
whereClause(NULL),
|
||||
groupBy(NULL),
|
||||
unionSelect(NULL),
|
||||
order(NULL),
|
||||
limit(NULL) {};
|
||||
|
||||
SelectStatement::~SelectStatement() {
|
||||
delete fromTable;
|
||||
delete selectList;
|
||||
delete whereClause;
|
||||
delete groupBy;
|
||||
delete order;
|
||||
delete limit;
|
||||
}
|
||||
|
||||
// UpdateStatement
|
||||
UpdateStatement::UpdateStatement() :
|
||||
SQLStatement(kStmtUpdate),
|
||||
table(NULL),
|
||||
updates(NULL),
|
||||
where(NULL) {}
|
||||
|
||||
UpdateStatement::~UpdateStatement() {
|
||||
delete table;
|
||||
delete updates;
|
||||
delete where;
|
||||
}
|
||||
|
||||
// TableRef
|
||||
TableRef::TableRef(TableRefType type) :
|
||||
type(type),
|
||||
schema(NULL),
|
||||
name(NULL),
|
||||
alias(NULL),
|
||||
select(NULL),
|
||||
list(NULL),
|
||||
join(NULL) {}
|
||||
|
||||
TableRef::~TableRef() {
|
||||
delete name;
|
||||
delete alias;
|
||||
delete select;
|
||||
delete list;
|
||||
}
|
||||
|
||||
bool TableRef::hasSchema() {
|
||||
return schema != NULL;
|
||||
}
|
||||
|
||||
char* TableRef::getName() {
|
||||
if (alias != NULL) return alias;
|
||||
else return name;
|
||||
}
|
||||
|
||||
// JoinDefinition
|
||||
JoinDefinition::JoinDefinition() :
|
||||
left(NULL),
|
||||
right(NULL),
|
||||
condition(NULL),
|
||||
type(kJoinInner) {}
|
||||
|
||||
JoinDefinition::~JoinDefinition() {
|
||||
delete left;
|
||||
delete right;
|
||||
delete condition;
|
||||
}
|
||||
|
||||
} // namespace hsql
|
|
@ -62,9 +62,9 @@ namespace hsql {
|
|||
return;
|
||||
}
|
||||
|
||||
switch (expr->op_type) {
|
||||
switch (expr->opType) {
|
||||
case Expr::SIMPLE_OP:
|
||||
inprintC(expr->op_char, numIndent);
|
||||
inprintC(expr->opChar, numIndent);
|
||||
break;
|
||||
case Expr::AND:
|
||||
inprint("AND", numIndent);
|
||||
|
@ -76,7 +76,7 @@ namespace hsql {
|
|||
inprint("NOT", numIndent);
|
||||
break;
|
||||
default:
|
||||
inprintU(expr->op_type, numIndent);
|
||||
inprintU(expr->opType, numIndent);
|
||||
break;
|
||||
}
|
||||
printExpression(expr->expr, numIndent + 1);
|
||||
|
|
|
@ -3,20 +3,20 @@
|
|||
|
||||
|
||||
#define TEST_PARSE_SQL_QUERY(query, outputVar, numStatements) \
|
||||
SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
|
||||
ASSERT(outputVar->isValid); \
|
||||
const SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
|
||||
ASSERT(outputVar->isValid()); \
|
||||
ASSERT_EQ(outputVar->size(), numStatements);
|
||||
|
||||
|
||||
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, outputVar) \
|
||||
TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \
|
||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmtType); \
|
||||
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(0);
|
||||
const stmtClass* outputVar = (const stmtClass*) stmt_list->getStatement(0);
|
||||
|
||||
|
||||
#define TEST_CAST_STMT(stmt_list, stmt_index, stmtType, stmtClass, outputVar) \
|
||||
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmtType); \
|
||||
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(stmt_index);
|
||||
const stmtClass* outputVar = (const stmtClass*) stmt_list->getStatement(stmt_index);
|
||||
|
||||
|
||||
#endif
|
|
@ -67,15 +67,15 @@ int main(int argc, char *argv[]) {
|
|||
start = std::chrono::system_clock::now();
|
||||
|
||||
// Parsing
|
||||
SQLParserResult* stmt_list = SQLParser::parseSQLString(sql.c_str());
|
||||
SQLParserResult* result = SQLParser::parseSQLString(sql.c_str());
|
||||
|
||||
end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = end-start;
|
||||
double us = elapsed_seconds.count() * 1000 * 1000;
|
||||
|
||||
if (expectFalse == stmt_list->isValid) {
|
||||
if (expectFalse == result->isValid()) {
|
||||
printf("\033[0;31m{ failed}\033[0m\n");
|
||||
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", stmt_list->errorMsg, stmt_list->errorLine, stmt_list->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());
|
||||
numFailed++;
|
||||
} else {
|
||||
|
|
|
@ -11,12 +11,12 @@ using namespace hsql;
|
|||
|
||||
|
||||
TEST(DeleteStatementTest) {
|
||||
SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||
ASSERT(result->isValid);
|
||||
const SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||
ASSERT(result->isValid());
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
ASSERT(result->getStatement(0)->type() == kStmtDelete);
|
||||
|
||||
DeleteStatement* stmt = (DeleteStatement*) result->getStatement(0);
|
||||
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->expr);
|
||||
ASSERT(stmt->expr->isType(kExprOperator));
|
||||
|
@ -25,12 +25,12 @@ TEST(DeleteStatementTest) {
|
|||
}
|
||||
|
||||
TEST(CreateStatementTest) {
|
||||
SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||
ASSERT(result->isValid);
|
||||
const SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||
ASSERT(result->isValid());
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
|
||||
|
||||
CreateStatement* stmt = (CreateStatement*) result->getStatement(0);
|
||||
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0);
|
||||
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->columns);
|
||||
|
@ -47,12 +47,12 @@ TEST(CreateStatementTest) {
|
|||
|
||||
|
||||
TEST(UpdateStatementTest) {
|
||||
SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||
ASSERT(result->isValid);
|
||||
const SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||
ASSERT(result->isValid());
|
||||
ASSERT_EQ(result->size(), 1);
|
||||
ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
|
||||
|
||||
UpdateStatement* stmt = (UpdateStatement*) result->getStatement(0);
|
||||
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0);
|
||||
ASSERT_NOTNULL(stmt->table);
|
||||
ASSERT_STREQ(stmt->table->name, "students");
|
||||
|
||||
|
|
Loading…
Reference in New Issue