commit
9872603fe7
2
Makefile
2
Makefile
|
@ -60,7 +60,7 @@ $(LIB_BUILD): $(LIB_OBJ)
|
||||||
$(LIBLINKER) $(LIB_LFLAGS) $(LIB_BUILD) $(LIB_OBJ)
|
$(LIBLINKER) $(LIB_LFLAGS) $(LIB_BUILD) $(LIB_OBJ)
|
||||||
|
|
||||||
$(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp $(SRCPARSER)/bison_parser.cpp
|
$(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp $(SRCPARSER)/bison_parser.cpp
|
||||||
$(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration
|
$(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration -Wno-register
|
||||||
|
|
||||||
%.o: %.cpp $(PARSER_CPP) $(LIB_H)
|
%.o: %.cpp $(PARSER_CPP) $(LIB_H)
|
||||||
$(CXX) $(LIB_CFLAGS) -c -o $@ $<
|
$(CXX) $(LIB_CFLAGS) -c -o $@ $<
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
# bison's version is too old on OSX, allow user to pass in custom path
|
||||||
|
BISON?=bison
|
||||||
|
|
||||||
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) --version | head -n 1
|
||||||
bison bison_parser.y --output=bison_parser.cpp --defines=bison_parser.h --verbose
|
$(BISON) bison_parser.y --output=bison_parser.cpp --defines=bison_parser.h --verbose
|
||||||
|
|
||||||
flex_lexer.cpp: flex_lexer.l
|
flex_lexer.cpp: flex_lexer.l
|
||||||
@flex --version
|
@flex --version
|
||||||
|
@ -14,4 +16,4 @@ clean:
|
||||||
|
|
||||||
# Tests if the parser builds correctly and doesn't contain conflicts.
|
# Tests if the parser builds correctly and doesn't contain conflicts.
|
||||||
test:
|
test:
|
||||||
! bison bison_parser.y -v --output=conflict_test.cpp 2>&1 | grep "conflict" >&2
|
! $(BISON) bison_parser.y -v --output=conflict_test.cpp 2>&1 | grep "conflict" >&2
|
||||||
|
|
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 35 "bison_parser.y" /* yacc.c:1909 */
|
#line 35 "bison_parser.y" /* yacc.c:1915 */
|
||||||
|
|
||||||
// %code requires block
|
// %code requires block
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ extern int hsql_debug;
|
||||||
yylloc->first_column = yylloc->last_column; \
|
yylloc->first_column = yylloc->last_column; \
|
||||||
for(int i = 0; yytext[i] != '\0'; i++) { \
|
for(int i = 0; yytext[i] != '\0'; i++) { \
|
||||||
yylloc->total_column++; \
|
yylloc->total_column++; \
|
||||||
|
yylloc->string_length++; \
|
||||||
if(yytext[i] == '\n') { \
|
if(yytext[i] == '\n') { \
|
||||||
yylloc->last_line++; \
|
yylloc->last_line++; \
|
||||||
yylloc->last_column = 0; \
|
yylloc->last_column = 0; \
|
||||||
|
@ -71,7 +72,7 @@ extern int hsql_debug;
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#line 75 "bison_parser.h" /* yacc.c:1909 */
|
#line 76 "bison_parser.h" /* yacc.c:1915 */
|
||||||
|
|
||||||
/* Token type. */
|
/* Token type. */
|
||||||
#ifndef HSQL_TOKENTYPE
|
#ifndef HSQL_TOKENTYPE
|
||||||
|
@ -217,7 +218,7 @@ extern int hsql_debug;
|
||||||
|
|
||||||
union HSQL_STYPE
|
union HSQL_STYPE
|
||||||
{
|
{
|
||||||
#line 93 "bison_parser.y" /* yacc.c:1909 */
|
#line 95 "bison_parser.y" /* yacc.c:1915 */
|
||||||
|
|
||||||
double fval;
|
double fval;
|
||||||
int64_t ival;
|
int64_t ival;
|
||||||
|
@ -236,7 +237,7 @@ union HSQL_STYPE
|
||||||
hsql::PrepareStatement* prep_stmt;
|
hsql::PrepareStatement* prep_stmt;
|
||||||
hsql::ExecuteStatement* exec_stmt;
|
hsql::ExecuteStatement* exec_stmt;
|
||||||
hsql::ShowStatement* show_stmt;
|
hsql::ShowStatement* show_stmt;
|
||||||
|
|
||||||
hsql::TableName table_name;
|
hsql::TableName table_name;
|
||||||
hsql::TableRef* table;
|
hsql::TableRef* table;
|
||||||
hsql::Expr* expr;
|
hsql::Expr* expr;
|
||||||
|
@ -256,7 +257,7 @@ union HSQL_STYPE
|
||||||
std::vector<hsql::Expr*>* expr_vec;
|
std::vector<hsql::Expr*>* expr_vec;
|
||||||
std::vector<hsql::OrderDescription*>* order_vec;
|
std::vector<hsql::OrderDescription*>* order_vec;
|
||||||
|
|
||||||
#line 260 "bison_parser.h" /* yacc.c:1909 */
|
#line 261 "bison_parser.h" /* yacc.c:1915 */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union HSQL_STYPE HSQL_STYPE;
|
typedef union HSQL_STYPE HSQL_STYPE;
|
||||||
|
|
|
@ -45,6 +45,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
yylloc->first_column = yylloc->last_column; \
|
yylloc->first_column = yylloc->last_column; \
|
||||||
for(int i = 0; yytext[i] != '\0'; i++) { \
|
for(int i = 0; yytext[i] != '\0'; i++) { \
|
||||||
yylloc->total_column++; \
|
yylloc->total_column++; \
|
||||||
|
yylloc->string_length++; \
|
||||||
if(yytext[i] == '\n') { \
|
if(yytext[i] == '\n') { \
|
||||||
yylloc->last_line++; \
|
yylloc->last_line++; \
|
||||||
yylloc->last_column = 0; \
|
yylloc->last_column = 0; \
|
||||||
|
@ -76,6 +77,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
@$.first_line = 0;
|
@$.first_line = 0;
|
||||||
@$.last_line = 0;
|
@$.last_line = 0;
|
||||||
@$.total_column = 0;
|
@$.total_column = 0;
|
||||||
|
@$.string_length = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,7 +110,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
hsql::PrepareStatement* prep_stmt;
|
hsql::PrepareStatement* prep_stmt;
|
||||||
hsql::ExecuteStatement* exec_stmt;
|
hsql::ExecuteStatement* exec_stmt;
|
||||||
hsql::ShowStatement* show_stmt;
|
hsql::ShowStatement* show_stmt;
|
||||||
|
|
||||||
hsql::TableName table_name;
|
hsql::TableName table_name;
|
||||||
hsql::TableRef* table;
|
hsql::TableRef* table;
|
||||||
hsql::Expr* expr;
|
hsql::Expr* expr;
|
||||||
|
@ -133,7 +135,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
/*********************************
|
/*********************************
|
||||||
** Descrutor symbols
|
** Descrutor symbols
|
||||||
*********************************/
|
*********************************/
|
||||||
%destructor { } <fval> <ival> <uval> <bval> <order_type>
|
%destructor { } <fval> <ival> <uval> <bval> <order_type>
|
||||||
%destructor { free( ($$.name) ); free( ($$.schema) ); } <table_name>
|
%destructor { free( ($$.name) ); free( ($$.schema) ); } <table_name>
|
||||||
%destructor { free( ($$) ); } <sval>
|
%destructor { free( ($$) ); } <sval>
|
||||||
%destructor {
|
%destructor {
|
||||||
|
@ -185,7 +187,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
%type <delete_stmt> delete_statement truncate_statement
|
%type <delete_stmt> delete_statement truncate_statement
|
||||||
%type <update_stmt> update_statement
|
%type <update_stmt> update_statement
|
||||||
%type <drop_stmt> drop_statement
|
%type <drop_stmt> drop_statement
|
||||||
%type <show_stmt> show_statement
|
%type <show_stmt> show_statement
|
||||||
%type <table_name> table_name
|
%type <table_name> table_name
|
||||||
%type <sval> opt_alias alias file_path prepare_target_query
|
%type <sval> opt_alias alias file_path prepare_target_query
|
||||||
%type <bval> opt_not_exists opt_exists opt_distinct
|
%type <bval> opt_not_exists opt_exists opt_distinct
|
||||||
|
@ -195,7 +197,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
|
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
|
||||||
%type <expr> function_expr between_expr expr_alias param_expr
|
%type <expr> function_expr between_expr expr_alias param_expr
|
||||||
%type <expr> column_name literal int_literal num_literal string_literal
|
%type <expr> column_name literal int_literal num_literal string_literal
|
||||||
%type <expr> comp_expr opt_where join_condition opt_having case_expr in_expr hint
|
%type <expr> comp_expr opt_where join_condition opt_having case_expr case_list in_expr hint
|
||||||
%type <expr> array_expr array_index null_literal
|
%type <expr> array_expr array_index null_literal
|
||||||
%type <limit> opt_limit opt_top
|
%type <limit> opt_limit opt_top
|
||||||
%type <order> order_desc
|
%type <order> order_desc
|
||||||
|
@ -263,8 +265,18 @@ input:
|
||||||
|
|
||||||
|
|
||||||
statement_list:
|
statement_list:
|
||||||
statement { $$ = new std::vector<SQLStatement*>(); $$->push_back($1); }
|
statement {
|
||||||
| statement_list ';' statement { $1->push_back($3); $$ = $1; }
|
$1->stringLength = yylloc.string_length;
|
||||||
|
yylloc.string_length = 0;
|
||||||
|
$$ = new std::vector<SQLStatement*>();
|
||||||
|
$$->push_back($1);
|
||||||
|
}
|
||||||
|
| statement_list ';' statement {
|
||||||
|
$3->stringLength = yylloc.string_length;
|
||||||
|
yylloc.string_length = 0;
|
||||||
|
$1->push_back($3);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
statement:
|
statement:
|
||||||
|
@ -471,7 +483,7 @@ opt_exists:
|
||||||
IF EXISTS { $$ = true; }
|
IF EXISTS { $$ = true; }
|
||||||
| /* empty */ { $$ = false; }
|
| /* empty */ { $$ = false; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
* Delete Statement / Truncate statement
|
* Delete Statement / Truncate statement
|
||||||
* DELETE FROM students WHERE grade > 3.0
|
* DELETE FROM students WHERE grade > 3.0
|
||||||
|
@ -781,11 +793,18 @@ in_expr:
|
||||||
| operand NOT IN '(' select_no_paren ')' { $$ = Expr::makeOpUnary(kOpNot, Expr::makeInOperator($1, $5)); }
|
| operand NOT IN '(' select_no_paren ')' { $$ = Expr::makeOpUnary(kOpNot, Expr::makeInOperator($1, $5)); }
|
||||||
;
|
;
|
||||||
|
|
||||||
// TODO: allow no else specified
|
// CASE grammar based on: flex & bison by John Levine
|
||||||
|
// https://www.safaribooksonline.com/library/view/flex-bison/9780596805418/ch04.html#id352665
|
||||||
case_expr:
|
case_expr:
|
||||||
CASE WHEN expr THEN operand END { $$ = Expr::makeCase($3, $5); }
|
CASE expr case_list END { $$ = Expr::makeCase($2, $3, nullptr); }
|
||||||
|
|
| CASE expr case_list ELSE expr END { $$ = Expr::makeCase($2, $3, $5); }
|
||||||
CASE WHEN expr THEN operand ELSE operand END { $$ = Expr::makeCase($3, $5, $7); }
|
| CASE case_list END { $$ = Expr::makeCase(nullptr, $2, nullptr); }
|
||||||
|
| CASE case_list ELSE expr END { $$ = Expr::makeCase(nullptr, $2, $4); }
|
||||||
|
;
|
||||||
|
|
||||||
|
case_list:
|
||||||
|
WHEN expr THEN expr { $$ = Expr::makeCaseList(Expr::makeCaseListElement($2, $4)); }
|
||||||
|
| case_list WHEN expr THEN expr { $$ = Expr::caseListAppend($1, Expr::makeCaseListElement($3, $5)); }
|
||||||
;
|
;
|
||||||
|
|
||||||
exists_expr:
|
exists_expr:
|
||||||
|
@ -865,10 +884,10 @@ param_expr:
|
||||||
******************************/
|
******************************/
|
||||||
table_ref:
|
table_ref:
|
||||||
table_ref_atomic
|
table_ref_atomic
|
||||||
| table_ref_atomic ',' table_ref_commalist {
|
| table_ref_commalist ',' table_ref_atomic {
|
||||||
$3->push_back($1);
|
$1->push_back($3);
|
||||||
auto tbl = new TableRef(kTableCrossProduct);
|
auto tbl = new TableRef(kTableCrossProduct);
|
||||||
tbl->list = $3;
|
tbl->list = $1;
|
||||||
$$ = tbl;
|
$$ = tbl;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -22,6 +22,9 @@ struct HSQL_CUST_LTYPE {
|
||||||
|
|
||||||
int total_column;
|
int total_column;
|
||||||
|
|
||||||
|
// Length of the string in the SQL query string
|
||||||
|
int string_length;
|
||||||
|
|
||||||
// Parameters.
|
// Parameters.
|
||||||
// int param_id;
|
// int param_id;
|
||||||
std::vector<void*> param_list;
|
std::vector<void*> param_list;
|
||||||
|
|
|
@ -68,22 +68,35 @@ namespace hsql {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeCase(Expr* expr, Expr* then) {
|
Expr* Expr::makeCaseList(Expr* caseListElement) {
|
||||||
Expr* e = new Expr(kExprOperator);
|
Expr* e = new Expr(kExprOperator);
|
||||||
e->expr = expr;
|
e->opType = kOpCaseList;
|
||||||
e->opType = kOpCase;
|
|
||||||
e->exprList = new std::vector<Expr*>();
|
e->exprList = new std::vector<Expr*>();
|
||||||
e->exprList->push_back(then);
|
e->exprList->push_back(caseListElement);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeCase(Expr* expr, Expr* then, Expr* other) {
|
Expr* Expr::makeCaseListElement(Expr* when, Expr* then) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->opType = kOpCaseListElement;
|
||||||
|
e->expr = when;
|
||||||
|
e->expr2 = then;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::caseListAppend(Expr* caseList, Expr* caseListElement) {
|
||||||
|
caseList->exprList->push_back(caseListElement);
|
||||||
|
return caseList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeCase(Expr* expr, Expr* caseList, Expr* elseExpr) {
|
||||||
Expr* e = new Expr(kExprOperator);
|
Expr* e = new Expr(kExprOperator);
|
||||||
e->expr = expr;
|
|
||||||
e->opType = kOpCase;
|
e->opType = kOpCase;
|
||||||
e->exprList = new std::vector<Expr*>();
|
e->expr = expr;
|
||||||
e->exprList->push_back(then);
|
e->expr2 = elseExpr;
|
||||||
e->exprList->push_back(other);
|
e->exprList = caseList->exprList;
|
||||||
|
caseList->exprList = nullptr;
|
||||||
|
delete caseList;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,22 @@ namespace hsql {
|
||||||
kExprSelect,
|
kExprSelect,
|
||||||
kExprHint,
|
kExprHint,
|
||||||
kExprArray,
|
kExprArray,
|
||||||
kExprArrayIndex
|
kExprArrayIndex,
|
||||||
|
kExprCaseList,
|
||||||
|
kExprCaseListElement
|
||||||
};
|
};
|
||||||
|
|
||||||
// Operator types. These are important for expressions of type kExprOperator.
|
// Operator types. These are important for expressions of type kExprOperator.
|
||||||
enum OperatorType {
|
enum OperatorType {
|
||||||
kOpNone,
|
kOpNone,
|
||||||
|
|
||||||
// Ternary operators
|
// Ternary operator
|
||||||
kOpBetween,
|
kOpBetween,
|
||||||
|
|
||||||
|
// n-nary special case
|
||||||
kOpCase,
|
kOpCase,
|
||||||
|
kOpCaseList, // Contains n >= 1 kExprCaseListElement in its exprList
|
||||||
|
kOpCaseListElement, // `WHEN expr THEN expr`
|
||||||
|
|
||||||
// Binary operators.
|
// Binary operators.
|
||||||
kOpPlus,
|
kOpPlus,
|
||||||
|
@ -113,9 +119,13 @@ namespace hsql {
|
||||||
|
|
||||||
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
||||||
|
|
||||||
static Expr* makeCase(Expr* expr, Expr* then);
|
static Expr* makeCaseList(Expr* caseListElement);
|
||||||
|
|
||||||
static Expr* makeCase(Expr* expr, Expr* then, Expr* other);
|
static Expr* makeCaseListElement(Expr* when, Expr* then);
|
||||||
|
|
||||||
|
static Expr* caseListAppend(Expr* caseList, Expr* caseListElement);
|
||||||
|
|
||||||
|
static Expr* makeCase(Expr* expr, Expr* when, Expr* elseExpr);
|
||||||
|
|
||||||
static Expr* makeLiteral(int64_t val);
|
static Expr* makeLiteral(int64_t val);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ namespace hsql {
|
||||||
// Shorthand for isType(type).
|
// Shorthand for isType(type).
|
||||||
bool is(StatementType type) const;
|
bool is(StatementType type) const;
|
||||||
|
|
||||||
|
// Length of the string in the SQL query string
|
||||||
|
size_t stringLength;
|
||||||
|
|
||||||
std::vector<Expr*>* hints;
|
std::vector<Expr*>* hints;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -214,9 +214,74 @@ TEST(SelectCaseWhen) {
|
||||||
ASSERT_NOTNULL(caseExpr);
|
ASSERT_NOTNULL(caseExpr);
|
||||||
ASSERT(caseExpr->isType(kExprOperator));
|
ASSERT(caseExpr->isType(kExprOperator));
|
||||||
ASSERT_EQ(caseExpr->opType, kOpCase);
|
ASSERT_EQ(caseExpr->opType, kOpCase);
|
||||||
ASSERT(caseExpr->expr->isType(kExprOperator));
|
ASSERT_NULL(caseExpr->expr);
|
||||||
ASSERT_EQ(caseExpr->expr->opType, kOpEquals);
|
ASSERT_NOTNULL(caseExpr->exprList);
|
||||||
|
ASSERT_NOTNULL(caseExpr->expr2);
|
||||||
|
ASSERT_EQ(caseExpr->exprList->size(), 1);
|
||||||
|
ASSERT(caseExpr->expr2->isType(kExprLiteralInt));
|
||||||
|
|
||||||
|
Expr* whenExpr = caseExpr->exprList->at(0);
|
||||||
|
ASSERT(whenExpr->expr->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(whenExpr->expr->opType, kOpEquals);
|
||||||
|
ASSERT(whenExpr->expr->expr->isType(kExprColumnRef));
|
||||||
|
ASSERT(whenExpr->expr->expr2->isType(kExprLiteralString));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SelectCaseWhenWhen) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT CASE WHEN x = 1 THEN 1 WHEN 1.25 < x THEN 2 END FROM test;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||||
|
Expr* caseExpr = stmt->selectList->at(0);
|
||||||
|
ASSERT_NOTNULL(caseExpr);
|
||||||
|
ASSERT(caseExpr->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(caseExpr->opType, kOpCase);
|
||||||
|
// CASE [expr] [exprList] [expr2]
|
||||||
|
// [expr] [expr]
|
||||||
|
// [expr] [expr2] [expr] [expr2]
|
||||||
|
// CASE (null) WHEN X = 1 THEN 1 WHEN 1.25 < x THEN 2 (null)
|
||||||
|
ASSERT_NULL(caseExpr->expr);
|
||||||
|
ASSERT_NOTNULL(caseExpr->exprList);
|
||||||
|
ASSERT_NULL(caseExpr->expr2);
|
||||||
ASSERT_EQ(caseExpr->exprList->size(), 2);
|
ASSERT_EQ(caseExpr->exprList->size(), 2);
|
||||||
|
|
||||||
|
Expr* whenExpr = caseExpr->exprList->at(0);
|
||||||
|
ASSERT_EQ(whenExpr->expr->opType, kOpEquals);
|
||||||
|
ASSERT(whenExpr->expr->expr->isType(kExprColumnRef));
|
||||||
|
ASSERT(whenExpr->expr->expr2->isType(kExprLiteralInt));
|
||||||
|
|
||||||
|
Expr* whenExpr2 = caseExpr->exprList->at(1);
|
||||||
|
ASSERT_EQ(whenExpr2->expr->opType, kOpLess);
|
||||||
|
ASSERT(whenExpr2->expr->expr->isType(kExprLiteralFloat));
|
||||||
|
ASSERT(whenExpr2->expr->expr2->isType(kExprColumnRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SelectCaseValueWhenWhenElse) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT CASE x WHEN 1 THEN 0 WHEN 2 THEN 3 WHEN 8 THEN 7 ELSE 4 END FROM test;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||||
|
Expr* caseExpr = stmt->selectList->at(0);
|
||||||
|
ASSERT_NOTNULL(caseExpr);
|
||||||
|
ASSERT(caseExpr->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(caseExpr->opType, kOpCase);
|
||||||
|
ASSERT_NOTNULL(caseExpr->expr);
|
||||||
|
ASSERT_NOTNULL(caseExpr->exprList);
|
||||||
|
ASSERT_NOTNULL(caseExpr->expr2);
|
||||||
|
ASSERT_EQ(caseExpr->exprList->size(), 3);
|
||||||
|
ASSERT(caseExpr->expr->isType(kExprColumnRef));
|
||||||
|
|
||||||
|
Expr* whenExpr = caseExpr->exprList->at(2);
|
||||||
|
ASSERT(whenExpr->expr->isType(kExprLiteralInt));
|
||||||
|
ASSERT_EQ(whenExpr->expr2->ival, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectJoin) {
|
TEST(SelectJoin) {
|
||||||
|
@ -260,3 +325,25 @@ TEST(SelectJoin) {
|
||||||
ASSERT_STREQ(inner_join->condition->expr2->table, "City");
|
ASSERT_STREQ(inner_join->condition->expr2->table, "City");
|
||||||
ASSERT_STREQ(inner_join->condition->expr2->name, "id");
|
ASSERT_STREQ(inner_join->condition->expr2->name, "id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SelectColumnOrder) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT *\
|
||||||
|
FROM a,\
|
||||||
|
(SELECT a AS b FROM a) b,\
|
||||||
|
(SELECT a AS c FROM a) c,\
|
||||||
|
(SELECT a AS d FROM a) d;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->fromTable->list->size(), 4);
|
||||||
|
|
||||||
|
// Make sure the order of the table list is corrects
|
||||||
|
ASSERT_STREQ(stmt->fromTable->list->at(0)->name, "a");
|
||||||
|
ASSERT_STREQ(stmt->fromTable->list->at(1)->alias, "b");
|
||||||
|
ASSERT_STREQ(stmt->fromTable->list->at(2)->alias, "c");
|
||||||
|
ASSERT_STREQ(stmt->fromTable->list->at(3)->alias, "d");
|
||||||
|
}
|
||||||
|
|
|
@ -213,4 +213,15 @@ TEST(HintTest) {
|
||||||
ASSERT_EQ(10, stmt->hints->at(1)->exprList->at(0)->ival);
|
ASSERT_EQ(10, stmt->hints->at(1)->exprList->at(0)->ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StringLengthTest) {
|
||||||
|
TEST_PARSE_SQL_QUERY(
|
||||||
|
"SELECT * FROM bar; INSERT INTO foo VALUES (4);\t\n SELECT * FROM foo;",
|
||||||
|
result,
|
||||||
|
3);
|
||||||
|
|
||||||
|
ASSERT_EQ(result.getStatement(0)->stringLength, 18);
|
||||||
|
ASSERT_EQ(result.getStatement(1)->stringLength, 28);
|
||||||
|
ASSERT_EQ(result.getStatement(2)->stringLength, 21);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_MAIN();
|
TEST_MAIN();
|
||||||
|
|
Loading…
Reference in New Issue