commit
353e25ae00
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
||||||
TESTCPP = $(shell find test/ -name '*.cpp')
|
TESTCPP = $(shell find test/ -name '*.cpp')
|
||||||
|
|
||||||
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
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')
|
ALLTEST = $(shell find test/ -name '*.cpp') $(shell find test/ -name '*.h')
|
||||||
|
|
||||||
# compile & link flages
|
# compile & link flages
|
||||||
CFLAGS = -std=c++11 -Wall -fPIC -g
|
CFLAGS = -std=c++11 -Wall -fPIC -g
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -131,6 +131,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
std::vector<hsql::ColumnDefinition*>* column_vec;
|
std::vector<hsql::ColumnDefinition*>* column_vec;
|
||||||
std::vector<hsql::UpdateClause*>* update_vec;
|
std::vector<hsql::UpdateClause*>* update_vec;
|
||||||
std::vector<hsql::Expr*>* expr_vec;
|
std::vector<hsql::Expr*>* expr_vec;
|
||||||
|
std::vector<hsql::OrderDescription*>* order_vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete ($$);
|
delete ($$);
|
||||||
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec>
|
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec> <order_vec>
|
||||||
%destructor { delete ($$); } <*>
|
%destructor { delete ($$); } <*>
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,12 +169,11 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
|
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
|
||||||
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
||||||
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
||||||
%token OUTER RIGHT TABLE UNION USING WHERE CALL DATE DESC
|
%token OUTER RIGHT TABLE UNION USING WHERE CALL CASE DATE
|
||||||
%token DROP FILE FROM FULL HASH HINT INTO JOIN LEFT LIKE
|
%token DESC DROP ELSE FILE FROM FULL HASH HINT INTO JOIN
|
||||||
%token LOAD NULL PART PLAN SHOW TEXT TIME VIEW WITH ADD ALL
|
%token LEFT LIKE LOAD NULL PART PLAN SHOW TEXT THEN TIME
|
||||||
%token AND ASC CSV FOR INT KEY NOT OFF SET TBL TOP AS BY IF
|
%token VIEW WHEN WITH ADD ALL AND ASC CSV END FOR INT KEY
|
||||||
%token IN IS OF ON OR TO
|
%token NOT OFF SET TBL TOP AS BY IF IN IS OF ON OR TO
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
||||||
|
@ -194,11 +194,12 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
%type <uval> import_file_type opt_join_type column_type
|
%type <uval> import_file_type opt_join_type column_type
|
||||||
%type <table> from_clause table_ref table_ref_atomic table_ref_name
|
%type <table> from_clause table_ref table_ref_atomic table_ref_name
|
||||||
%type <table> join_clause join_table table_ref_name_no_alias
|
%type <table> join_clause join_table table_ref_name_no_alias
|
||||||
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias placeholder_expr
|
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
|
||||||
|
%type <expr> function_expr between_expr star_expr expr_alias placeholder_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
|
%type <expr> comp_expr opt_where join_condition opt_having case_expr in_expr
|
||||||
%type <order> opt_order
|
%type <limit> opt_limit opt_top
|
||||||
%type <limit> opt_limit
|
%type <order> order_desc
|
||||||
%type <order_type> opt_order_type
|
%type <order_type> opt_order_type
|
||||||
%type <column_t> column_def
|
%type <column_t> column_def
|
||||||
%type <update_t> update_clause
|
%type <update_t> update_clause
|
||||||
|
@ -207,6 +208,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
%type <str_vec> ident_commalist opt_column_list
|
%type <str_vec> ident_commalist opt_column_list
|
||||||
%type <expr_vec> expr_list select_list literal_list
|
%type <expr_vec> expr_list select_list literal_list
|
||||||
%type <table_vec> table_ref_commalist
|
%type <table_vec> table_ref_commalist
|
||||||
|
%type <order_vec> opt_order order_list
|
||||||
%type <update_vec> update_clause_commalist
|
%type <update_vec> update_clause_commalist
|
||||||
%type <column_vec> column_def_commalist
|
%type <column_vec> column_def_commalist
|
||||||
|
|
||||||
|
@ -476,7 +478,12 @@ select_no_paren:
|
||||||
select_clause opt_order opt_limit {
|
select_clause opt_order opt_limit {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->order = $2;
|
$$->order = $2;
|
||||||
$$->limit = $3;
|
|
||||||
|
// Limit could have been set by TOP.
|
||||||
|
if ($3 != NULL) {
|
||||||
|
delete $$->limit;
|
||||||
|
$$->limit = $3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| select_clause set_operator select_clause opt_order opt_limit {
|
| select_clause set_operator select_clause opt_order opt_limit {
|
||||||
// TODO: allow multiple unions (through linked list)
|
// TODO: allow multiple unions (through linked list)
|
||||||
|
@ -485,13 +492,23 @@ select_no_paren:
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->unionSelect = $3;
|
$$->unionSelect = $3;
|
||||||
$$->order = $4;
|
$$->order = $4;
|
||||||
$$->limit = $5;
|
|
||||||
|
// Limit could have been set by TOP.
|
||||||
|
if ($5 != NULL) {
|
||||||
|
delete $$->limit;
|
||||||
|
$$->limit = $5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| select_clause set_operator select_with_paren opt_order opt_limit {
|
| select_clause set_operator select_with_paren opt_order opt_limit {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->unionSelect = $3;
|
$$->unionSelect = $3;
|
||||||
$$->order = $4;
|
$$->order = $4;
|
||||||
$$->limit = $5;
|
|
||||||
|
// Limit could have been set by TOP.
|
||||||
|
if ($5 != NULL) {
|
||||||
|
delete $$->limit;
|
||||||
|
$$->limit = $5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -502,13 +519,14 @@ set_operator:
|
||||||
;
|
;
|
||||||
|
|
||||||
select_clause:
|
select_clause:
|
||||||
SELECT opt_distinct select_list from_clause opt_where opt_group {
|
SELECT opt_top opt_distinct select_list from_clause opt_where opt_group {
|
||||||
$$ = new SelectStatement();
|
$$ = new SelectStatement();
|
||||||
$$->selectDistinct = $2;
|
$$->limit = $2;
|
||||||
$$->selectList = $3;
|
$$->selectDistinct = $3;
|
||||||
$$->fromTable = $4;
|
$$->selectList = $4;
|
||||||
$$->whereClause = $5;
|
$$->fromTable = $5;
|
||||||
$$->groupBy = $6;
|
$$->whereClause = $6;
|
||||||
|
$$->groupBy = $7;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -521,7 +539,6 @@ select_list:
|
||||||
expr_list
|
expr_list
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
from_clause:
|
from_clause:
|
||||||
FROM table_ref { $$ = $2; }
|
FROM table_ref { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
@ -546,16 +563,31 @@ opt_having:
|
||||||
| /* empty */ { $$ = NULL; }
|
| /* empty */ { $$ = NULL; }
|
||||||
|
|
||||||
opt_order:
|
opt_order:
|
||||||
ORDER BY expr opt_order_type { $$ = new OrderDescription($4, $3); }
|
ORDER BY order_list { $$ = $3; }
|
||||||
| /* empty */ { $$ = NULL; }
|
| /* empty */ { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
order_list:
|
||||||
|
order_desc { $$ = new std::vector<OrderDescription*>(); $$->push_back($1); }
|
||||||
|
| order_list ',' order_desc { $1->push_back($3); $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
order_desc:
|
||||||
|
expr opt_order_type { $$ = new OrderDescription($2, $1); }
|
||||||
|
;
|
||||||
|
|
||||||
opt_order_type:
|
opt_order_type:
|
||||||
ASC { $$ = kOrderAsc; }
|
ASC { $$ = kOrderAsc; }
|
||||||
| DESC { $$ = kOrderDesc; }
|
| DESC { $$ = kOrderDesc; }
|
||||||
| /* empty */ { $$ = kOrderAsc; }
|
| /* empty */ { $$ = kOrderAsc; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// TODO: TOP and LIMIT can take more than just int literals.
|
||||||
|
|
||||||
|
opt_top:
|
||||||
|
TOP int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
||||||
|
| /* empty */ { $$ = NULL; }
|
||||||
|
;
|
||||||
|
|
||||||
opt_limit:
|
opt_limit:
|
||||||
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
||||||
|
@ -584,11 +616,21 @@ expr_alias:
|
||||||
;
|
;
|
||||||
|
|
||||||
expr:
|
expr:
|
||||||
|
operand
|
||||||
|
| between_expr
|
||||||
|
| logic_expr
|
||||||
|
| exists_expr
|
||||||
|
| case_expr
|
||||||
|
| in_expr
|
||||||
|
;
|
||||||
|
|
||||||
|
operand:
|
||||||
'(' expr ')' { $$ = $2; }
|
'(' expr ')' { $$ = $2; }
|
||||||
| scalar_expr
|
| scalar_expr
|
||||||
| unary_expr
|
| unary_expr
|
||||||
| binary_expr
|
| binary_expr
|
||||||
| function_expr
|
| function_expr
|
||||||
|
| '(' select_no_paren ')' { $$ = Expr::makeSelect($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
scalar_expr:
|
scalar_expr:
|
||||||
|
@ -598,36 +640,59 @@ scalar_expr:
|
||||||
;
|
;
|
||||||
|
|
||||||
unary_expr:
|
unary_expr:
|
||||||
'-' expr { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); }
|
'-' operand { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); }
|
||||||
| NOT expr { $$ = Expr::makeOpUnary(Expr::NOT, $2); }
|
| NOT operand { $$ = Expr::makeOpUnary(Expr::NOT, $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
binary_expr:
|
binary_expr:
|
||||||
comp_expr
|
comp_expr
|
||||||
| expr '-' expr { $$ = Expr::makeOpBinary($1, '-', $3); }
|
| operand '-' operand { $$ = Expr::makeOpBinary($1, '-', $3); }
|
||||||
| expr '+' expr { $$ = Expr::makeOpBinary($1, '+', $3); }
|
| operand '+' operand { $$ = Expr::makeOpBinary($1, '+', $3); }
|
||||||
| expr '/' expr { $$ = Expr::makeOpBinary($1, '/', $3); }
|
| operand '/' operand { $$ = Expr::makeOpBinary($1, '/', $3); }
|
||||||
| expr '*' expr { $$ = Expr::makeOpBinary($1, '*', $3); }
|
| operand '*' operand { $$ = Expr::makeOpBinary($1, '*', $3); }
|
||||||
| expr '%' expr { $$ = Expr::makeOpBinary($1, '%', $3); }
|
| operand '%' operand { $$ = Expr::makeOpBinary($1, '%', $3); }
|
||||||
| expr '^' expr { $$ = Expr::makeOpBinary($1, '^', $3); }
|
| operand '^' operand { $$ = Expr::makeOpBinary($1, '^', $3); }
|
||||||
| expr AND expr { $$ = Expr::makeOpBinary($1, Expr::AND, $3); }
|
| operand LIKE operand { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); }
|
||||||
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
| operand NOT LIKE operand { $$ = Expr::makeOpBinary($1, Expr::NOT_LIKE, $4); }
|
||||||
| expr LIKE expr { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); }
|
|
||||||
| expr NOT LIKE expr { $$ = Expr::makeOpBinary($1, Expr::NOT_LIKE, $4); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
logic_expr:
|
||||||
|
expr AND expr { $$ = Expr::makeOpBinary($1, Expr::AND, $3); }
|
||||||
|
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
in_expr:
|
||||||
|
operand IN '(' expr_list ')' { $$ = Expr::makeInOperator($1, $4); }
|
||||||
|
| operand NOT IN '(' expr_list ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeInOperator($1, $5)); }
|
||||||
|
| operand IN '(' select_no_paren ')' { $$ = Expr::makeInOperator($1, $4); }
|
||||||
|
| operand NOT IN '(' select_no_paren ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeInOperator($1, $5)); }
|
||||||
|
;
|
||||||
|
|
||||||
|
// TODO: allow no else specified
|
||||||
|
case_expr:
|
||||||
|
CASE WHEN expr THEN operand ELSE operand END { $$ = Expr::makeCase($3, $5, $7); }
|
||||||
|
;
|
||||||
|
|
||||||
|
exists_expr:
|
||||||
|
EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); }
|
||||||
|
| NOT EXISTS '(' select_no_paren ')' { $$ = Expr::makeOpUnary(Expr::NOT, Expr::makeExists($4)); }
|
||||||
|
;
|
||||||
|
|
||||||
comp_expr:
|
comp_expr:
|
||||||
expr '=' expr { $$ = Expr::makeOpBinary($1, '=', $3); }
|
operand '=' operand { $$ = Expr::makeOpBinary($1, '=', $3); }
|
||||||
| expr NOTEQUALS expr { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }
|
| operand NOTEQUALS operand { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }
|
||||||
| expr '<' expr { $$ = Expr::makeOpBinary($1, '<', $3); }
|
| operand '<' operand { $$ = Expr::makeOpBinary($1, '<', $3); }
|
||||||
| expr '>' expr { $$ = Expr::makeOpBinary($1, '>', $3); }
|
| operand '>' operand { $$ = Expr::makeOpBinary($1, '>', $3); }
|
||||||
| expr LESSEQ expr { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); }
|
| operand LESSEQ operand { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); }
|
||||||
| expr GREATEREQ expr { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); }
|
| operand GREATEREQ operand { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
function_expr:
|
function_expr:
|
||||||
IDENTIFIER '(' opt_distinct expr ')' { $$ = Expr::makeFunctionRef($1, $4, $3); }
|
IDENTIFIER '(' opt_distinct expr_list ')' { $$ = Expr::makeFunctionRef($1, $4, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
between_expr:
|
||||||
|
operand BETWEEN operand AND operand { $$ = Expr::makeBetween($1, $3, $5); }
|
||||||
;
|
;
|
||||||
|
|
||||||
column_name:
|
column_name:
|
||||||
|
@ -659,7 +724,6 @@ star_expr:
|
||||||
'*' { $$ = new Expr(kExprStar); }
|
'*' { $$ = new Expr(kExprStar); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
placeholder_expr:
|
placeholder_expr:
|
||||||
'?' {
|
'?' {
|
||||||
$$ = Expr::makePlaceholder(yylloc.total_column);
|
$$ = Expr::makePlaceholder(yylloc.total_column);
|
||||||
|
@ -751,11 +815,15 @@ join_clause:
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_join_type:
|
opt_join_type:
|
||||||
INNER { $$ = kJoinInner; }
|
INNER { $$ = kJoinInner; }
|
||||||
| OUTER { $$ = kJoinOuter; }
|
| OUTER { $$ = kJoinOuter; }
|
||||||
| LEFT { $$ = kJoinLeft; }
|
| LEFT OUTER { $$ = kJoinLeftOuter; }
|
||||||
| RIGHT { $$ = kJoinRight; }
|
| RIGHT OUTER { $$ = kJoinRightOuter; }
|
||||||
| /* empty, default */ { $$ = kJoinInner; }
|
| LEFT { $$ = kJoinLeft; }
|
||||||
|
| RIGHT { $$ = kJoinRight; }
|
||||||
|
| CROSS { $$ = kJoinCross; }
|
||||||
|
| NATURAL { $$ = kJoinNatural; }
|
||||||
|
| /* empty, default */ { $$ = kJoinInner; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,8 @@
|
||||||
<COMMENT>[^\n]* /* skipping comment content until a end of line is read */;
|
<COMMENT>[^\n]* /* skipping comment content until a end of line is read */;
|
||||||
<COMMENT>\n BEGIN(INITIAL);
|
<COMMENT>\n BEGIN(INITIAL);
|
||||||
|
|
||||||
|
|
||||||
[ \t\n]+ /* skip whitespace */;
|
[ \t\n]+ /* skip whitespace */;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DEALLOCATE TOKEN(DEALLOCATE)
|
DEALLOCATE TOKEN(DEALLOCATE)
|
||||||
PARAMETERS TOKEN(PARAMETERS)
|
PARAMETERS TOKEN(PARAMETERS)
|
||||||
INTERSECT TOKEN(INTERSECT)
|
INTERSECT TOKEN(INTERSECT)
|
||||||
|
@ -127,9 +124,11 @@ UNION TOKEN(UNION)
|
||||||
USING TOKEN(USING)
|
USING TOKEN(USING)
|
||||||
WHERE TOKEN(WHERE)
|
WHERE TOKEN(WHERE)
|
||||||
CALL TOKEN(CALL)
|
CALL TOKEN(CALL)
|
||||||
|
CASE TOKEN(CASE)
|
||||||
DATE TOKEN(DATE)
|
DATE TOKEN(DATE)
|
||||||
DESC TOKEN(DESC)
|
DESC TOKEN(DESC)
|
||||||
DROP TOKEN(DROP)
|
DROP TOKEN(DROP)
|
||||||
|
ELSE TOKEN(ELSE)
|
||||||
FILE TOKEN(FILE)
|
FILE TOKEN(FILE)
|
||||||
FROM TOKEN(FROM)
|
FROM TOKEN(FROM)
|
||||||
FULL TOKEN(FULL)
|
FULL TOKEN(FULL)
|
||||||
|
@ -145,14 +144,17 @@ PART TOKEN(PART)
|
||||||
PLAN TOKEN(PLAN)
|
PLAN TOKEN(PLAN)
|
||||||
SHOW TOKEN(SHOW)
|
SHOW TOKEN(SHOW)
|
||||||
TEXT TOKEN(TEXT)
|
TEXT TOKEN(TEXT)
|
||||||
|
THEN TOKEN(THEN)
|
||||||
TIME TOKEN(TIME)
|
TIME TOKEN(TIME)
|
||||||
VIEW TOKEN(VIEW)
|
VIEW TOKEN(VIEW)
|
||||||
|
WHEN TOKEN(WHEN)
|
||||||
WITH TOKEN(WITH)
|
WITH TOKEN(WITH)
|
||||||
ADD TOKEN(ADD)
|
ADD TOKEN(ADD)
|
||||||
ALL TOKEN(ALL)
|
ALL TOKEN(ALL)
|
||||||
AND TOKEN(AND)
|
AND TOKEN(AND)
|
||||||
ASC TOKEN(ASC)
|
ASC TOKEN(ASC)
|
||||||
CSV TOKEN(CSV)
|
CSV TOKEN(CSV)
|
||||||
|
END TOKEN(END)
|
||||||
FOR TOKEN(FOR)
|
FOR TOKEN(FOR)
|
||||||
INT TOKEN(INT)
|
INT TOKEN(INT)
|
||||||
KEY TOKEN(KEY)
|
KEY TOKEN(KEY)
|
||||||
|
@ -171,15 +173,12 @@ ON TOKEN(ON)
|
||||||
OR TOKEN(OR)
|
OR TOKEN(OR)
|
||||||
TO TOKEN(TO)
|
TO TOKEN(TO)
|
||||||
|
|
||||||
|
|
||||||
"<>" TOKEN(NOTEQUALS)
|
"<>" TOKEN(NOTEQUALS)
|
||||||
"<=" TOKEN(LESSEQ)
|
"<=" TOKEN(LESSEQ)
|
||||||
">=" TOKEN(GREATEREQ)
|
">=" TOKEN(GREATEREQ)
|
||||||
|
|
||||||
|
|
||||||
[-+*/(){},.;<>=^%:?] { return yytext[0]; }
|
[-+*/(){},.;<>=^%:?] { return yytext[0]; }
|
||||||
|
|
||||||
|
|
||||||
[0-9]+"."[0-9]* |
|
[0-9]+"."[0-9]* |
|
||||||
"."[0-9]* {
|
"."[0-9]* {
|
||||||
yylval->fval = atof(yytext);
|
yylval->fval = atof(yytext);
|
||||||
|
@ -202,7 +201,6 @@ TO TOKEN(TO)
|
||||||
return SQL_IDENTIFIER;
|
return SQL_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
'[^'\n]*' {
|
'[^'\n]*' {
|
||||||
// Crop the leading and trailing quote char
|
// Crop the leading and trailing quote char
|
||||||
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
||||||
|
|
|
@ -140,6 +140,11 @@ IS
|
||||||
ISNULL
|
ISNULL
|
||||||
BETWEEN
|
BETWEEN
|
||||||
ESCAPE
|
ESCAPE
|
||||||
|
CASE
|
||||||
|
WHEN
|
||||||
|
THEN
|
||||||
|
ELSE
|
||||||
|
END
|
||||||
|
|
||||||
// With
|
// With
|
||||||
WITH
|
WITH
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Expr.h"
|
#include "Expr.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "SelectStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ namespace hsql {
|
||||||
type(type),
|
type(type),
|
||||||
expr(NULL),
|
expr(NULL),
|
||||||
expr2(NULL),
|
expr2(NULL),
|
||||||
|
exprList(NULL),
|
||||||
|
select(NULL),
|
||||||
name(NULL),
|
name(NULL),
|
||||||
table(NULL),
|
table(NULL),
|
||||||
alias(NULL) {};
|
alias(NULL) {};
|
||||||
|
@ -16,9 +19,17 @@ namespace hsql {
|
||||||
Expr::~Expr() {
|
Expr::~Expr() {
|
||||||
delete expr;
|
delete expr;
|
||||||
delete expr2;
|
delete expr2;
|
||||||
|
delete select;
|
||||||
free(name);
|
free(name);
|
||||||
free(table);
|
free(table);
|
||||||
free(alias);
|
free(alias);
|
||||||
|
|
||||||
|
if (exprList != NULL) {
|
||||||
|
for (Expr* e : *exprList) {
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
delete exprList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||||
|
@ -47,6 +58,26 @@ namespace hsql {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeBetween(Expr* expr, Expr* left, Expr* right) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->expr = expr;
|
||||||
|
e->opType = BETWEEN;
|
||||||
|
e->exprList = new std::vector<Expr*>();
|
||||||
|
e->exprList->push_back(left);
|
||||||
|
e->exprList->push_back(right);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeCase(Expr* expr, Expr* then, Expr* other) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->expr = expr;
|
||||||
|
e->opType = CASE;
|
||||||
|
e->exprList = new std::vector<Expr*>();
|
||||||
|
e->exprList->push_back(then);
|
||||||
|
e->exprList->push_back(other);
|
||||||
|
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;
|
||||||
|
@ -79,10 +110,10 @@ namespace hsql {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) {
|
Expr* Expr::makeFunctionRef(char* func_name, std::vector<Expr*>* exprList, bool distinct) {
|
||||||
Expr* e = new Expr(kExprFunctionRef);
|
Expr* e = new Expr(kExprFunctionRef);
|
||||||
e->name = func_name;
|
e->name = func_name;
|
||||||
e->expr = expr;
|
e->exprList = exprList;
|
||||||
e->distinct = distinct;
|
e->distinct = distinct;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +124,37 @@ namespace hsql {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeSelect(SelectStatement* select) {
|
||||||
|
Expr* e = new Expr(kExprSelect);
|
||||||
|
e->select = select;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeExists(SelectStatement* select) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->opType = EXISTS;
|
||||||
|
e->select = select;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeInOperator(Expr* expr, std::vector<Expr*>* exprList) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->opType = IN;
|
||||||
|
e->expr = expr;
|
||||||
|
e->exprList = exprList;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeInOperator(Expr* expr, SelectStatement* select) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->opType = IN;
|
||||||
|
e->expr = expr;
|
||||||
|
e->select = select;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
bool Expr::isType(ExprType e_type) {
|
bool Expr::isType(ExprType e_type) {
|
||||||
return e_type == type;
|
return e_type == type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
class SelectStatement;
|
||||||
|
|
||||||
// Helper function used by the lexer.
|
// Helper function used by the lexer.
|
||||||
// TODO: move to more appropriate place.
|
// TODO: move to more appropriate place.
|
||||||
|
@ -18,7 +20,8 @@ namespace hsql {
|
||||||
kExprPlaceholder,
|
kExprPlaceholder,
|
||||||
kExprColumnRef,
|
kExprColumnRef,
|
||||||
kExprFunctionRef,
|
kExprFunctionRef,
|
||||||
kExprOperator
|
kExprOperator,
|
||||||
|
kExprSelect
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Expr Expr;
|
typedef struct Expr Expr;
|
||||||
|
@ -31,9 +34,14 @@ namespace hsql {
|
||||||
// + - * / < > = %
|
// + - * / < > = %
|
||||||
// Non-trivial are: <> <= >= LIKE ISNULL NOT
|
// Non-trivial are: <> <= >= LIKE ISNULL NOT
|
||||||
enum OperatorType {
|
enum OperatorType {
|
||||||
SIMPLE_OP,
|
NONE,
|
||||||
|
|
||||||
|
// Ternary operators
|
||||||
|
BETWEEN,
|
||||||
|
CASE,
|
||||||
|
|
||||||
// Binary operators.
|
// Binary operators.
|
||||||
|
SIMPLE_OP,
|
||||||
NOT_EQUALS,
|
NOT_EQUALS,
|
||||||
LESS_EQ,
|
LESS_EQ,
|
||||||
GREATER_EQ,
|
GREATER_EQ,
|
||||||
|
@ -41,11 +49,13 @@ namespace hsql {
|
||||||
NOT_LIKE,
|
NOT_LIKE,
|
||||||
AND,
|
AND,
|
||||||
OR,
|
OR,
|
||||||
|
IN,
|
||||||
|
|
||||||
// Unary operators.
|
// Unary operators.
|
||||||
NOT,
|
NOT,
|
||||||
UMINUS,
|
UMINUS,
|
||||||
ISNULL
|
ISNULL,
|
||||||
|
EXISTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,8 +69,11 @@ namespace hsql {
|
||||||
|
|
||||||
ExprType type;
|
ExprType type;
|
||||||
|
|
||||||
|
// TODO: Replace expressions by list.
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
Expr* expr2;
|
Expr* expr2;
|
||||||
|
std::vector<Expr*>* exprList;
|
||||||
|
SelectStatement* select;
|
||||||
char* name;
|
char* name;
|
||||||
char* table;
|
char* table;
|
||||||
char* alias;
|
char* alias;
|
||||||
|
@ -72,6 +85,7 @@ namespace hsql {
|
||||||
char opChar;
|
char opChar;
|
||||||
bool distinct;
|
bool distinct;
|
||||||
|
|
||||||
|
|
||||||
// Convenience accessor methods.
|
// Convenience accessor methods.
|
||||||
|
|
||||||
bool isType(ExprType e_type);
|
bool isType(ExprType e_type);
|
||||||
|
@ -97,6 +111,10 @@ namespace hsql {
|
||||||
|
|
||||||
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
||||||
|
|
||||||
|
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
||||||
|
|
||||||
|
static Expr* makeCase(Expr* expr, Expr* then, Expr* other);
|
||||||
|
|
||||||
static Expr* makeLiteral(int64_t val);
|
static Expr* makeLiteral(int64_t val);
|
||||||
|
|
||||||
static Expr* makeLiteral(double val);
|
static Expr* makeLiteral(double val);
|
||||||
|
@ -107,9 +125,17 @@ namespace hsql {
|
||||||
|
|
||||||
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, std::vector<Expr*>* exprList, bool distinct);
|
||||||
|
|
||||||
static Expr* makePlaceholder(int id);
|
static Expr* makePlaceholder(int id);
|
||||||
|
|
||||||
|
static Expr* makeSelect(SelectStatement* select);
|
||||||
|
|
||||||
|
static Expr* makeExists(SelectStatement* select);
|
||||||
|
|
||||||
|
static Expr* makeInOperator(Expr* expr, std::vector<Expr*>* exprList);
|
||||||
|
|
||||||
|
static Expr* makeInOperator(Expr* expr, SelectStatement* select);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace hsql {
|
||||||
GroupByDescription* groupBy;
|
GroupByDescription* groupBy;
|
||||||
|
|
||||||
SelectStatement* unionSelect;
|
SelectStatement* unionSelect;
|
||||||
OrderDescription* order;
|
std::vector<OrderDescription*>* order;
|
||||||
LimitDescription* limit;
|
LimitDescription* limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,10 @@ namespace hsql {
|
||||||
kJoinOuter,
|
kJoinOuter,
|
||||||
kJoinLeft,
|
kJoinLeft,
|
||||||
kJoinRight,
|
kJoinRight,
|
||||||
|
kJoinLeftOuter,
|
||||||
|
kJoinRightOuter,
|
||||||
|
kJoinCross,
|
||||||
|
kJoinNatural
|
||||||
};
|
};
|
||||||
|
|
||||||
// Definition of a join construct.
|
// Definition of a join construct.
|
||||||
|
|
|
@ -138,7 +138,7 @@ namespace hsql {
|
||||||
placeholders.push_back((Expr*) e);
|
placeholders.push_back((Expr*) e);
|
||||||
}
|
}
|
||||||
// Sort by col-id
|
// Sort by col-id
|
||||||
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
std::sort(placeholders.begin(), placeholders.end(), [](Expr * i, Expr * j) -> bool { return (i->ival < j->ival); });
|
||||||
|
|
||||||
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||||
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
for (uintmax_t i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||||
|
@ -193,7 +193,6 @@ namespace hsql {
|
||||||
delete whereClause;
|
delete whereClause;
|
||||||
delete groupBy;
|
delete groupBy;
|
||||||
delete unionSelect;
|
delete unionSelect;
|
||||||
delete order;
|
|
||||||
delete limit;
|
delete limit;
|
||||||
|
|
||||||
// Delete each element in the select list.
|
// Delete each element in the select list.
|
||||||
|
@ -203,6 +202,13 @@ namespace hsql {
|
||||||
}
|
}
|
||||||
delete selectList;
|
delete selectList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (order != NULL) {
|
||||||
|
for (OrderDescription* desc : *order) {
|
||||||
|
delete desc;
|
||||||
|
}
|
||||||
|
delete order;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatement
|
// UpdateStatement
|
||||||
|
|
|
@ -139,8 +139,8 @@ namespace hsql {
|
||||||
|
|
||||||
if (stmt->order != NULL) {
|
if (stmt->order != NULL) {
|
||||||
inprint("OrderBy:", numIndent + 1);
|
inprint("OrderBy:", numIndent + 1);
|
||||||
printExpression(stmt->order->expr, numIndent + 2);
|
printExpression(stmt->order->at(0)->expr, numIndent + 2);
|
||||||
if (stmt->order->type == kOrderAsc) inprint("ascending", numIndent + 2);
|
if (stmt->order->at(0)->type == kOrderAsc) inprint("ascending", numIndent + 2);
|
||||||
else inprint("descending", numIndent + 2);
|
else inprint("descending", numIndent + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT L_RETURNFLAG, L_LINESTATUS, SUM(L_QUANTITY) AS SUM_QTY,
|
||||||
|
SUM(L_EXTENDEDPRICE) AS SUM_BASE_PRICE, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS SUM_DISC_PRICE,
|
||||||
|
SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)*(1+L_TAX)) AS SUM_CHARGE, AVG(L_QUANTITY) AS AVG_QTY,
|
||||||
|
AVG(L_EXTENDEDPRICE) AS AVG_PRICE, AVG(L_DISCOUNT) AS AVG_DISC, COUNT(*) AS COUNT_ORDER
|
||||||
|
FROM LINEITEM
|
||||||
|
WHERE L_SHIPDATE <= dateadd(dd, -90, cast('1998-12-01' as datetime))
|
||||||
|
GROUP BY L_RETURNFLAG, L_LINESTATUS
|
||||||
|
ORDER BY L_RETURNFLAG,L_LINESTATUS
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT TOP 100 S_ACCTBAL, S_NAME, N_NAME, P_PARTKEY, P_MFGR, S_ADDRESS, S_PHONE, S_COMMENT
|
||||||
|
FROM "PART", SUPPLIER, PARTSUPP, NATION, REGION
|
||||||
|
WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY AND P_SIZE = 15 AND
|
||||||
|
P_TYPE LIKE '%%BRASS' AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND
|
||||||
|
R_NAME = 'EUROPE' AND
|
||||||
|
PS_SUPPLYCOST = (SELECT MIN(PS_SUPPLYCOST) FROM PARTSUPP, SUPPLIER, NATION, REGION
|
||||||
|
WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY
|
||||||
|
AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND R_NAME = 'EUROPE')
|
||||||
|
ORDER BY S_ACCTBAL DESC, N_NAME, S_NAME, P_PARTKEY
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT TOP 10 L_ORDERKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, O_ORDERDATE, O_SHIPPRIORITY
|
||||||
|
FROM CUSTOMER, ORDERS, LINEITEM
|
||||||
|
WHERE C_MKTSEGMENT = 'BUILDING' AND C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND
|
||||||
|
O_ORDERDATE < '1995-03-15' AND L_SHIPDATE > '1995-03-15'
|
||||||
|
GROUP BY L_ORDERKEY, O_ORDERDATE, O_SHIPPRIORITY
|
||||||
|
ORDER BY REVENUE DESC, O_ORDERDATE;
|
|
@ -0,0 +1,6 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT O_ORDERPRIORITY, COUNT(*) AS ORDER_COUNT FROM ORDERS
|
||||||
|
WHERE O_ORDERDATE >= '1993-07-01' AND O_ORDERDATE < dateadd(mm,3, cast('1993-07-01' as datetime))
|
||||||
|
AND EXISTS (SELECT * FROM LINEITEM WHERE L_ORDERKEY = O_ORDERKEY AND L_COMMITDATE < L_RECEIPTDATE)
|
||||||
|
GROUP BY O_ORDERPRIORITY
|
||||||
|
ORDER BY O_ORDERPRIORITY
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT N_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE
|
||||||
|
FROM CUSTOMER, ORDERS, LINEITEM, SUPPLIER, NATION, REGION
|
||||||
|
WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND L_SUPPKEY = S_SUPPKEY
|
||||||
|
AND C_NATIONKEY = S_NATIONKEY AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY
|
||||||
|
AND R_NAME = 'ASIA' AND O_ORDERDATE >= '1994-01-01'
|
||||||
|
AND O_ORDERDATE < DATEADD(YY, 1, cast('1994-01-01' as datetime))
|
||||||
|
GROUP BY N_NAME
|
||||||
|
ORDER BY REVENUE DESC
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT SUM(L_EXTENDEDPRICE*L_DISCOUNT) AS REVENUE
|
||||||
|
FROM LINEITEM
|
||||||
|
WHERE L_SHIPDATE >= '1994-01-01' AND L_SHIPDATE < dateadd(yy, 1, cast('1994-01-01' as datetime))
|
||||||
|
AND L_DISCOUNT BETWEEN .06 - 0.01 AND .06 + 0.01 AND L_QUANTITY < 24
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT SUPP_NATION, CUST_NATION, L_YEAR, SUM(VOLUME) AS REVENUE
|
||||||
|
FROM ( SELECT N1.N_NAME AS SUPP_NATION, N2.N_NAME AS CUST_NATION, datepart(yy, L_SHIPDATE) AS L_YEAR,
|
||||||
|
L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME
|
||||||
|
FROM SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2
|
||||||
|
WHERE S_SUPPKEY = L_SUPPKEY AND O_ORDERKEY = L_ORDERKEY AND C_CUSTKEY = O_CUSTKEY
|
||||||
|
AND S_NATIONKEY = N1.N_NATIONKEY AND C_NATIONKEY = N2.N_NATIONKEY AND ((N1.N_NAME = 'FRANCE' AND N2.N_NAME = 'GERMANY') OR
|
||||||
|
(N1.N_NAME = 'GERMANY' AND N2.N_NAME = 'FRANCE')) AND
|
||||||
|
L_SHIPDATE BETWEEN '1995-01-01' AND '1996-12-31' ) AS SHIPPING
|
||||||
|
GROUP BY SUPP_NATION, CUST_NATION, L_YEAR
|
||||||
|
ORDER BY SUPP_NATION, CUST_NATION, L_YEAR
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT O_YEAR, SUM(CASE WHEN NATION = 'BRAZIL' THEN VOLUME ELSE 0 END)/SUM(VOLUME) AS MKT_SHARE
|
||||||
|
FROM (SELECT datepart(yy,O_ORDERDATE) AS O_YEAR, L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME, N2.N_NAME AS NATION
|
||||||
|
FROM "PART", SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2, REGION
|
||||||
|
WHERE P_PARTKEY = L_PARTKEY AND S_SUPPKEY = L_SUPPKEY AND L_ORDERKEY = O_ORDERKEY
|
||||||
|
AND O_CUSTKEY = C_CUSTKEY AND C_NATIONKEY = N1.N_NATIONKEY AND
|
||||||
|
N1.N_REGIONKEY = R_REGIONKEY AND R_NAME = 'AMERICA' AND S_NATIONKEY = N2.N_NATIONKEY
|
||||||
|
AND O_ORDERDATE BETWEEN '1995-01-01' AND '1996-12-31' AND P_TYPE= 'ECONOMY ANODIZED STEEL') AS ALL_NATIONS
|
||||||
|
GROUP BY O_YEAR
|
||||||
|
ORDER BY O_YEAR
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT NATION, O_YEAR, SUM(AMOUNT) AS SUM_PROFIT
|
||||||
|
FROM (SELECT N_NAME AS NATION, datepart(yy, O_ORDERDATE) AS O_YEAR,
|
||||||
|
L_EXTENDEDPRICE*(1-L_DISCOUNT)-PS_SUPPLYCOST*L_QUANTITY AS AMOUNT
|
||||||
|
FROM "PART", SUPPLIER, LINEITEM, PARTSUPP, ORDERS, NATION
|
||||||
|
WHERE S_SUPPKEY = L_SUPPKEY AND PS_SUPPKEY= L_SUPPKEY AND PS_PARTKEY = L_PARTKEY AND
|
||||||
|
P_PARTKEY= L_PARTKEY AND O_ORDERKEY = L_ORDERKEY AND S_NATIONKEY = N_NATIONKEY AND
|
||||||
|
P_NAME LIKE '%%green%%') AS PROFIT
|
||||||
|
GROUP BY NATION, O_YEAR
|
||||||
|
ORDER BY NATION, O_YEAR DESC
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
SELECT TOP 20 C_CUSTKEY, C_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, C_ACCTBAL,
|
||||||
|
N_NAME, C_ADDRESS, C_PHONE, C_COMMENT
|
||||||
|
FROM CUSTOMER, ORDERS, LINEITEM, NATION
|
||||||
|
WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND O_ORDERDATE>= '1993-10-01' AND
|
||||||
|
O_ORDERDATE < dateadd(mm, 3, cast('1993-10-01' as datetime)) AND
|
||||||
|
L_RETURNFLAG = 'R' AND C_NATIONKEY = N_NATIONKEY
|
||||||
|
GROUP BY C_CUSTKEY, C_NAME, C_ACCTBAL, C_PHONE, N_NAME, C_ADDRESS, C_COMMENT
|
||||||
|
ORDER BY REVENUE DESC
|
|
@ -0,0 +1,59 @@
|
||||||
|
-- From:
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
|
||||||
|
-- TPC_H Query 11 - Important Stock Identification
|
||||||
|
SELECT PS_PARTKEY, SUM(PS_SUPPLYCOST*PS_AVAILQTY) AS VALUE
|
||||||
|
FROM PARTSUPP, SUPPLIER, NATION
|
||||||
|
WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY'
|
||||||
|
GROUP BY PS_PARTKEY
|
||||||
|
HAVING SUM(PS_SUPPLYCOST*PS_AVAILQTY) > (SELECT SUM(PS_SUPPLYCOST*PS_AVAILQTY) * 0.0001000000
|
||||||
|
FROM PARTSUPP, SUPPLIER, NATION
|
||||||
|
WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY')
|
||||||
|
ORDER BY VALUE DESC;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 12 - Shipping Modes and Order Priority
|
||||||
|
SELECT L_SHIPMODE,
|
||||||
|
SUM(CASE WHEN O_ORDERPRIORITY = '1-URGENT' OR O_ORDERPRIORITY = '2-HIGH' THEN 1 ELSE 0 END) AS HIGH_LINE_COUNT,
|
||||||
|
SUM(CASE WHEN O_ORDERPRIORITY <> '1-URGENT' AND O_ORDERPRIORITY <> '2-HIGH' THEN 1 ELSE 0 END ) AS LOW_LINE_COUNT
|
||||||
|
FROM ORDERS, LINEITEM
|
||||||
|
WHERE O_ORDERKEY = L_ORDERKEY AND L_SHIPMODE IN ('MAIL','SHIP')
|
||||||
|
AND L_COMMITDATE < L_RECEIPTDATE AND L_SHIPDATE < L_COMMITDATE AND L_RECEIPTDATE >= '1994-01-01'
|
||||||
|
AND L_RECEIPTDATE < dateadd(mm, 1, cast('1995-09-01' as datetime))
|
||||||
|
GROUP BY L_SHIPMODE
|
||||||
|
ORDER BY L_SHIPMODE;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 13 - Customer Distribution
|
||||||
|
SELECT C_COUNT, COUNT(*) AS CUSTDIST
|
||||||
|
FROM (SELECT C_CUSTKEY, COUNT(O_ORDERKEY)
|
||||||
|
FROM CUSTOMER left outer join ORDERS on C_CUSTKEY = O_CUSTKEY
|
||||||
|
AND O_COMMENT not like '%%special%%requests%%'
|
||||||
|
GROUP BY C_CUSTKEY) AS C_ORDERS
|
||||||
|
GROUP BY C_COUNT
|
||||||
|
ORDER BY CUSTDIST DESC, C_COUNT DESC;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 14 - Promotion Effect
|
||||||
|
SELECT 100.00* SUM(CASE WHEN P_TYPE LIKE 'PROMO%%' THEN L_EXTENDEDPRICE*(1-L_DISCOUNT)
|
||||||
|
ELSE 0 END) / SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS PROMO_REVENUE
|
||||||
|
FROM LINEITEM, "PART"
|
||||||
|
WHERE L_PARTKEY = P_PARTKEY AND L_SHIPDATE >= '1995-09-01' AND L_SHIPDATE < dateadd(mm, 1, '1995-09-01');
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 15.1 - Create View for Top Supplier Query
|
||||||
|
-- CREATE VIEW REVENUE0 (SUPPLIER_NO, TOTAL_REVENUE) AS
|
||||||
|
-- SELECT L_SUPPKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) FROM LINEITEM
|
||||||
|
-- WHERE L_SHIPDATE >= '1996-01-01' AND L_SHIPDATE < dateadd(mm, 3, cast('1996-01-01' as datetime))
|
||||||
|
-- GROUP BY L_SUPPKEY;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 15.2 - Top Supplier
|
||||||
|
SELECT S_SUPPKEY, S_NAME, S_ADDRESS, S_PHONE, TOTAL_REVENUE
|
||||||
|
FROM SUPPLIER, REVENUE0
|
||||||
|
WHERE S_SUPPKEY = SUPPLIER_NO AND TOTAL_REVENUE = (SELECT MAX(TOTAL_REVENUE) FROM REVENUE0)
|
||||||
|
ORDER BY S_SUPPKEY;
|
||||||
|
|
||||||
|
-- TPC_H Query 15.3 - Drop View
|
||||||
|
-- DROP VIEW REVENUE0;
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
-- From:
|
||||||
|
-- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html
|
||||||
|
|
||||||
|
-- TPC_H Query 16 - Parts/Supplier Relationship
|
||||||
|
SELECT P_BRAND, P_TYPE, P_SIZE, COUNT(DISTINCT PS_SUPPKEY) AS SUPPLIER_CNT
|
||||||
|
FROM PARTSUPP, "PART"
|
||||||
|
WHERE P_PARTKEY = PS_PARTKEY AND P_BRAND <> 'Brand#45' AND P_TYPE NOT LIKE 'MEDIUM POLISHED%%'
|
||||||
|
AND P_SIZE IN (49, 14, 23, 45, 19, 3, 36, 9) AND PS_SUPPKEY NOT IN (SELECT S_SUPPKEY FROM SUPPLIER
|
||||||
|
WHERE S_COMMENT LIKE '%%Customer%%Complaints%%')
|
||||||
|
GROUP BY P_BRAND, P_TYPE, P_SIZE
|
||||||
|
ORDER BY SUPPLIER_CNT DESC, P_BRAND, P_TYPE, P_SIZE;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 17 - Small-Quantity-Order Revenue
|
||||||
|
SELECT SUM(L_EXTENDEDPRICE)/7.0 AS AVG_YEARLY FROM LINEITEM, "PART"
|
||||||
|
WHERE P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#23' AND P_CONTAINER = 'MED BOX'
|
||||||
|
AND L_QUANTITY < (SELECT 0.2*AVG(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = P_PARTKEY);
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 18 - Large Volume Customer
|
||||||
|
SELECT TOP 100 C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE, SUM(L_QUANTITY)
|
||||||
|
FROM CUSTOMER, ORDERS, LINEITEM
|
||||||
|
WHERE O_ORDERKEY IN (SELECT L_ORDERKEY FROM LINEITEM GROUP BY L_ORDERKEY HAVING
|
||||||
|
SUM(L_QUANTITY) > 300) AND C_CUSTKEY = O_CUSTKEY AND O_ORDERKEY = L_ORDERKEY
|
||||||
|
GROUP BY C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE
|
||||||
|
ORDER BY O_TOTALPRICE DESC, O_ORDERDATE;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 19 - Discounted Revenue
|
||||||
|
SELECT SUM(L_EXTENDEDPRICE* (1 - L_DISCOUNT)) AS REVENUE
|
||||||
|
FROM LINEITEM, "PART"
|
||||||
|
WHERE (P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#12' AND P_CONTAINER IN ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG') AND L_QUANTITY >= 1 AND L_QUANTITY <= 1 + 10 AND P_SIZE BETWEEN 1 AND 5
|
||||||
|
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON')
|
||||||
|
OR (P_PARTKEY = L_PARTKEY AND P_BRAND ='Brand#23' AND P_CONTAINER IN ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') AND L_QUANTITY >=10 AND L_QUANTITY <=10 + 10 AND P_SIZE BETWEEN 1 AND 10
|
||||||
|
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON')
|
||||||
|
OR (P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#34' AND P_CONTAINER IN ( 'LG CASE', 'LG BOX', 'LG PACK', 'LG PKG') AND L_QUANTITY >=20 AND L_QUANTITY <= 20 + 10 AND P_SIZE BETWEEN 1 AND 15
|
||||||
|
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON');
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 20 - Potential Part Promotion
|
||||||
|
SELECT S_NAME, S_ADDRESS FROM SUPPLIER, NATION
|
||||||
|
WHERE S_SUPPKEY IN (SELECT PS_SUPPKEY FROM PARTSUPP
|
||||||
|
WHERE PS_PARTKEY in (SELECT P_PARTKEY FROM "PART" WHERE P_NAME like 'forest%%') AND
|
||||||
|
PS_AVAILQTY > (SELECT 0.5*sum(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = PS_PARTKEY AND
|
||||||
|
L_SUPPKEY = PS_SUPPKEY AND L_SHIPDATE >= '1994-01-01' AND
|
||||||
|
L_SHIPDATE < dateadd(yy,1,'1994-01-01'))) AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'CANADA'
|
||||||
|
ORDER BY S_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 21 - Suppliers Who Kept Orders Waiting
|
||||||
|
SELECT TOP 100 S_NAME, COUNT(*) AS NUMWAIT
|
||||||
|
FROM SUPPLIER, LINEITEM L1, ORDERS, NATION WHERE S_SUPPKEY = L1.L_SUPPKEY AND
|
||||||
|
O_ORDERKEY = L1.L_ORDERKEY AND O_ORDERSTATUS = 'F' AND L1.L_RECEIPTDATE> L1.L_COMMITDATE
|
||||||
|
AND EXISTS (SELECT * FROM LINEITEM L2 WHERE L2.L_ORDERKEY = L1.L_ORDERKEY
|
||||||
|
AND L2.L_SUPPKEY <> L1.L_SUPPKEY) AND
|
||||||
|
NOT EXISTS (SELECT * FROM LINEITEM L3 WHERE L3.L_ORDERKEY = L1.L_ORDERKEY AND
|
||||||
|
L3.L_SUPPKEY <> L1.L_SUPPKEY AND L3.L_RECEIPTDATE > L3.L_COMMITDATE) AND
|
||||||
|
S_NATIONKEY = N_NATIONKEY AND N_NAME = 'SAUDI ARABIA'
|
||||||
|
GROUP BY S_NAME
|
||||||
|
ORDER BY NUMWAIT DESC, S_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
-- TPC_H Query 22 - Global Sales Opportunity */
|
||||||
|
SELECT CNTRYCODE, COUNT(*) AS NUMCUST, SUM(C_ACCTBAL) AS TOTACCTBAL
|
||||||
|
FROM (SELECT SUBSTRING(C_PHONE,1,2) AS CNTRYCODE, C_ACCTBAL
|
||||||
|
FROM CUSTOMER WHERE SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17') AND
|
||||||
|
C_ACCTBAL > (SELECT AVG(C_ACCTBAL) FROM CUSTOMER WHERE C_ACCTBAL > 0.00 AND
|
||||||
|
SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17')) AND
|
||||||
|
NOT EXISTS ( SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)) AS CUSTSALE
|
||||||
|
GROUP BY CNTRYCODE
|
||||||
|
ORDER BY CNTRYCODE;
|
|
@ -20,6 +20,45 @@ TEST(SelectTest) {
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SelectExprTest) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT a, MAX(b), CUSTOM(c, F(un)) FROM students;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_NULL(stmt->whereClause);
|
||||||
|
ASSERT_NULL(stmt->groupBy);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->selectList->size(), 3);
|
||||||
|
|
||||||
|
ASSERT(stmt->selectList->at(0)->isType(kExprColumnRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(0)->getName(), "a");
|
||||||
|
|
||||||
|
ASSERT(stmt->selectList->at(1)->isType(kExprFunctionRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(1)->getName(), "MAX");
|
||||||
|
ASSERT_NOTNULL(stmt->selectList->at(1)->exprList);
|
||||||
|
ASSERT_EQ(stmt->selectList->at(1)->exprList->size(), 1);
|
||||||
|
ASSERT(stmt->selectList->at(1)->exprList->at(0)->isType(kExprColumnRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(1)->exprList->at(0)->getName(), "b");
|
||||||
|
|
||||||
|
ASSERT(stmt->selectList->at(2)->isType(kExprFunctionRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(2)->getName(), "CUSTOM");
|
||||||
|
ASSERT_NOTNULL(stmt->selectList->at(2)->exprList);
|
||||||
|
ASSERT_EQ(stmt->selectList->at(2)->exprList->size(), 2);
|
||||||
|
ASSERT(stmt->selectList->at(2)->exprList->at(0)->isType(kExprColumnRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(2)->exprList->at(0)->getName(), "c");
|
||||||
|
|
||||||
|
ASSERT(stmt->selectList->at(2)->exprList->at(1)->isType(kExprFunctionRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(2)->exprList->at(1)->getName(), "F");
|
||||||
|
ASSERT_EQ(stmt->selectList->at(2)->exprList->at(1)->exprList->size(), 1);
|
||||||
|
ASSERT(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->isType(kExprColumnRef));
|
||||||
|
ASSERT_STREQ(stmt->selectList->at(2)->exprList->at(1)->exprList->at(0)->getName(), "un");
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectHavingTest) {
|
TEST(SelectHavingTest) {
|
||||||
TEST_PARSE_SINGLE_SQL(
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
@ -72,4 +111,115 @@ TEST(SelectGroupDistinctTest) {
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(OrderByTest) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT grade, city FROM students ORDER BY grade, city DESC;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_NULL(stmt->whereClause);
|
||||||
|
ASSERT_NOTNULL(stmt->order);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->order->size(), 2);
|
||||||
|
ASSERT_EQ(stmt->order->at(0)->type, kOrderAsc);
|
||||||
|
ASSERT_STREQ(stmt->order->at(0)->expr->name, "grade");
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->order->at(1)->type, kOrderDesc);
|
||||||
|
ASSERT_STREQ(stmt->order->at(1)->expr->name, "city");
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SelectBetweenTest) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT grade, city FROM students WHERE grade BETWEEN 1 and c;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
|
||||||
|
Expr* where = stmt->whereClause;
|
||||||
|
ASSERT_NOTNULL(where);
|
||||||
|
ASSERT(where->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(where->opType, Expr::BETWEEN);
|
||||||
|
|
||||||
|
ASSERT_STREQ(where->expr->getName(), "grade");
|
||||||
|
ASSERT(where->expr->isType(kExprColumnRef));
|
||||||
|
|
||||||
|
ASSERT_EQ(where->exprList->size(), 2);
|
||||||
|
ASSERT(where->exprList->at(0)->isType(kExprLiteralInt));
|
||||||
|
ASSERT_EQ(where->exprList->at(0)->ival, 1);
|
||||||
|
ASSERT(where->exprList->at(1)->isType(kExprColumnRef));
|
||||||
|
ASSERT_STREQ(where->exprList->at(1)->getName(), "c");
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SelectConditionalSelectTest) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT * FROM t WHERE a = (SELECT MIN(v) FROM tt) AND EXISTS (SELECT * FROM test WHERE x < a);",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
Expr* where = stmt->whereClause;
|
||||||
|
ASSERT_NOTNULL(where);
|
||||||
|
ASSERT(where->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(where->opType, Expr::AND);
|
||||||
|
|
||||||
|
// a = (SELECT ...)
|
||||||
|
Expr* cond1 = where->expr;
|
||||||
|
ASSERT_NOTNULL(cond1);
|
||||||
|
ASSERT_NOTNULL(cond1->expr);
|
||||||
|
ASSERT(cond1->isSimpleOp('='));
|
||||||
|
ASSERT_STREQ(cond1->expr->getName(), "a");
|
||||||
|
ASSERT(cond1->expr->isType(kExprColumnRef));
|
||||||
|
|
||||||
|
ASSERT_NOTNULL(cond1->expr2);
|
||||||
|
ASSERT(cond1->expr2->isType(kExprSelect));
|
||||||
|
|
||||||
|
SelectStatement* select2 = cond1->expr2->select;
|
||||||
|
ASSERT_NOTNULL(select2);
|
||||||
|
ASSERT_STREQ(select2->fromTable->getName(), "tt");
|
||||||
|
|
||||||
|
|
||||||
|
// EXISTS (SELECT ...)
|
||||||
|
Expr* cond2 = where->expr2;
|
||||||
|
ASSERT_EQ(cond2->opType, Expr::EXISTS);
|
||||||
|
ASSERT_NOTNULL(cond2->select);
|
||||||
|
|
||||||
|
SelectStatement* ex_select = cond2->select;
|
||||||
|
ASSERT_STREQ(ex_select->fromTable->getName(), "test");
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SelectCaseWhen) {
|
||||||
|
TEST_PARSE_SINGLE_SQL(
|
||||||
|
"SELECT MAX(CASE WHEN a = 'foo' THEN x ELSE 0 END) FROM test;",
|
||||||
|
kStmtSelect,
|
||||||
|
SelectStatement,
|
||||||
|
result,
|
||||||
|
stmt);
|
||||||
|
|
||||||
|
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||||
|
Expr* func = stmt->selectList->at(0);
|
||||||
|
|
||||||
|
ASSERT_NOTNULL(func);
|
||||||
|
ASSERT(func->isType(kExprFunctionRef));
|
||||||
|
ASSERT_EQ(func->exprList->size(), 1);
|
||||||
|
|
||||||
|
Expr* caseExpr = func->exprList->at(0);
|
||||||
|
ASSERT_NOTNULL(caseExpr);
|
||||||
|
ASSERT(caseExpr->isType(kExprOperator));
|
||||||
|
ASSERT_EQ(caseExpr->opType, Expr::CASE);
|
||||||
|
ASSERT(caseExpr->expr->isType(kExprOperator));
|
||||||
|
ASSERT(caseExpr->expr->isSimpleOp('='));
|
||||||
|
ASSERT_EQ(caseExpr->exprList->size(), 2);
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
|
@ -13,96 +13,96 @@ using namespace hsql;
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> readlines(std::string path) {
|
std::vector<std::string> readlines(std::string path) {
|
||||||
std::ifstream infile(path);
|
std::ifstream infile(path);
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(infile, line)) {
|
while (std::getline(infile, line)) {
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
|
|
||||||
// Skip comments
|
// Skip comments
|
||||||
if (line[0] == '#' ||
|
if (line[0] == '#' ||
|
||||||
(line[0] == '-' && line[1] == '-')) {
|
(line[0] == '-' && line[1] == '-')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
lines.push_back(line);
|
|
||||||
}
|
}
|
||||||
return lines;
|
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
||||||
|
|
||||||
TEST(AutoGrammarTest) {
|
TEST(AutoGrammarTest) {
|
||||||
const std::vector<std::string>& args = mt::Runtime::args();
|
const std::vector<std::string>& args = mt::Runtime::args();
|
||||||
if (args.size() <= 1) {
|
if (args.size() <= 1) {
|
||||||
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool globalExpectFalse = false;
|
bool globalExpectFalse = false;
|
||||||
bool useFile = false;
|
bool useFile = false;
|
||||||
std::string filePath = "";
|
std::string filePath = "";
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
uint i = 1;
|
uint i = 1;
|
||||||
for (; i < args.size(); ++i) {
|
for (; i < args.size(); ++i) {
|
||||||
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
||||||
else if (STREQ(args[i], "-f")) {
|
else if (STREQ(args[i], "-f")) {
|
||||||
useFile = true;
|
useFile = true;
|
||||||
filePath = args[++i];
|
filePath = args[++i];
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Read list of queries for this rest
|
|
||||||
std::vector<std::string> queries;
|
|
||||||
if (useFile) {
|
|
||||||
queries = readlines(filePath);
|
|
||||||
} else {
|
} else {
|
||||||
for (; i < args.size(); ++i) queries.push_back(args[i]);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read list of queries for this rest
|
||||||
|
std::vector<std::string> queries;
|
||||||
|
if (useFile) {
|
||||||
|
queries = readlines(filePath);
|
||||||
|
} else {
|
||||||
|
for (; i < args.size(); ++i) queries.push_back(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Execute queries
|
||||||
|
int numFailed = 0;
|
||||||
|
for (std::string sql : queries) {
|
||||||
|
bool expectFalse = globalExpectFalse;
|
||||||
|
if (sql.at(0) == '!') {
|
||||||
|
expectFalse = !expectFalse;
|
||||||
|
sql = sql.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Measuring the parsing time
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||||
|
start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
// Execute queries
|
// Parsing
|
||||||
int numFailed = 0;
|
SQLParserResult* result = SQLParser::parseSQLString(sql.c_str());
|
||||||
for (std::string sql : queries) {
|
|
||||||
bool expectFalse = globalExpectFalse;
|
|
||||||
if (sql.at(0) == '!') {
|
|
||||||
expectFalse = !expectFalse;
|
|
||||||
sql = sql.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Measuring the parsing time
|
end = std::chrono::system_clock::now();
|
||||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
std::chrono::duration<double> elapsed_seconds = end - start;
|
||||||
start = std::chrono::system_clock::now();
|
double us = elapsed_seconds.count() * 1000 * 1000;
|
||||||
|
|
||||||
// Parsing
|
if (expectFalse == result->isValid()) {
|
||||||
SQLParserResult* result = SQLParser::parseSQLString(sql.c_str());
|
printf("\033[0;31m{ failed}\033[0m\n");
|
||||||
|
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result->errorMsg(), result->errorLine(), result->errorColumn());
|
||||||
end = std::chrono::system_clock::now();
|
printf("\t%s\n", sql.c_str());
|
||||||
std::chrono::duration<double> elapsed_seconds = end-start;
|
numFailed++;
|
||||||
double us = elapsed_seconds.count() * 1000 * 1000;
|
|
||||||
|
|
||||||
if (expectFalse == result->isValid()) {
|
|
||||||
printf("\033[0;31m{ failed}\033[0m\n");
|
|
||||||
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result->errorMsg(), result->errorLine(), result->errorColumn());
|
|
||||||
printf("\t%s\n", sql.c_str());
|
|
||||||
numFailed++;
|
|
||||||
} else {
|
|
||||||
// TODO: indicate whether expectFalse was set
|
|
||||||
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numFailed == 0) {
|
|
||||||
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
// TODO: indicate whether expectFalse was set
|
||||||
|
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
|
||||||
}
|
}
|
||||||
ASSERT_EQ(numFailed, 0);
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numFailed == 0) {
|
||||||
|
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
||||||
|
}
|
||||||
|
ASSERT_EQ(numFailed, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,160 +11,161 @@ using namespace hsql;
|
||||||
|
|
||||||
|
|
||||||
TEST(DeleteStatementTest) {
|
TEST(DeleteStatementTest) {
|
||||||
const SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
const SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||||
ASSERT(result->isValid());
|
ASSERT(result->isValid());
|
||||||
ASSERT_EQ(result->size(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT(result->getStatement(0)->type() == kStmtDelete);
|
ASSERT(result->getStatement(0)->type() == kStmtDelete);
|
||||||
|
|
||||||
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0);
|
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0);
|
||||||
ASSERT_STREQ(stmt->tableName, "students");
|
ASSERT_STREQ(stmt->tableName, "students");
|
||||||
ASSERT_NOTNULL(stmt->expr);
|
ASSERT_NOTNULL(stmt->expr);
|
||||||
ASSERT(stmt->expr->isType(kExprOperator));
|
ASSERT(stmt->expr->isType(kExprOperator));
|
||||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||||
ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
|
ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CreateStatementTest) {
|
TEST(CreateStatementTest) {
|
||||||
const SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
const SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||||
ASSERT(result->isValid());
|
ASSERT(result->isValid());
|
||||||
ASSERT_EQ(result->size(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
|
ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
|
||||||
|
|
||||||
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0);
|
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0);
|
||||||
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
||||||
ASSERT_STREQ(stmt->tableName, "students");
|
ASSERT_STREQ(stmt->tableName, "students");
|
||||||
ASSERT_NOTNULL(stmt->columns);
|
ASSERT_NOTNULL(stmt->columns);
|
||||||
ASSERT_EQ(stmt->columns->size(), 4);
|
ASSERT_EQ(stmt->columns->size(), 4);
|
||||||
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
||||||
ASSERT_STREQ(stmt->columns->at(1)->name, "student_number");
|
ASSERT_STREQ(stmt->columns->at(1)->name, "student_number");
|
||||||
ASSERT_STREQ(stmt->columns->at(2)->name, "city");
|
ASSERT_STREQ(stmt->columns->at(2)->name, "city");
|
||||||
ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
|
ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
|
||||||
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
|
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
|
||||||
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
|
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
|
||||||
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
|
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
|
||||||
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
|
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(UpdateStatementTest) {
|
TEST(UpdateStatementTest) {
|
||||||
const SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
const SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||||
ASSERT(result->isValid());
|
ASSERT(result->isValid());
|
||||||
ASSERT_EQ(result->size(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
|
ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
|
||||||
|
|
||||||
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0);
|
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0);
|
||||||
ASSERT_NOTNULL(stmt->table);
|
ASSERT_NOTNULL(stmt->table);
|
||||||
ASSERT_STREQ(stmt->table->name, "students");
|
ASSERT_STREQ(stmt->table->name, "students");
|
||||||
|
|
||||||
ASSERT_NOTNULL(stmt->updates);
|
ASSERT_NOTNULL(stmt->updates);
|
||||||
ASSERT_EQ(stmt->updates->size(), 2);
|
ASSERT_EQ(stmt->updates->size(), 2);
|
||||||
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
|
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
|
||||||
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
|
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
|
||||||
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
|
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
|
||||||
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
|
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
|
||||||
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
|
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
|
||||||
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
|
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
|
||||||
|
|
||||||
ASSERT_NOTNULL(stmt->where);
|
ASSERT_NOTNULL(stmt->where);
|
||||||
ASSERT(stmt->where->isType(kExprOperator));
|
ASSERT(stmt->where->isType(kExprOperator));
|
||||||
ASSERT(stmt->where->isSimpleOp('='));
|
ASSERT(stmt->where->isSimpleOp('='));
|
||||||
ASSERT_STREQ(stmt->where->expr->name, "name");
|
ASSERT_STREQ(stmt->where->expr->name, "name");
|
||||||
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");\
|
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");
|
||||||
|
\
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(InsertStatementTest) {
|
TEST(InsertStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL(
|
TEST_PARSE_SINGLE_SQL(
|
||||||
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
|
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
|
||||||
kStmtInsert,
|
kStmtInsert,
|
||||||
InsertStatement,
|
InsertStatement,
|
||||||
result,
|
result,
|
||||||
stmt);
|
stmt);
|
||||||
|
|
||||||
ASSERT_EQ(stmt->values->size(), 4);
|
ASSERT_EQ(stmt->values->size(), 4);
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(DropTableStatementTest) {
|
TEST(DropTableStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL(
|
TEST_PARSE_SINGLE_SQL(
|
||||||
"DROP TABLE students",
|
"DROP TABLE students",
|
||||||
kStmtDrop,
|
kStmtDrop,
|
||||||
DropStatement,
|
DropStatement,
|
||||||
result,
|
result,
|
||||||
stmt);
|
stmt);
|
||||||
|
|
||||||
ASSERT_EQ(stmt->type, DropStatement::kTable);
|
ASSERT_EQ(stmt->type, DropStatement::kTable);
|
||||||
ASSERT_NOTNULL(stmt->name);
|
ASSERT_NOTNULL(stmt->name);
|
||||||
ASSERT_STREQ(stmt->name, "students");
|
ASSERT_STREQ(stmt->name, "students");
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(PrepareStatementTest) {
|
TEST(PrepareStatementTest) {
|
||||||
std::string query = "PREPARE test {"
|
std::string query = "PREPARE test {"
|
||||||
"INSERT INTO test VALUES(?);"
|
"INSERT INTO test VALUES(?);"
|
||||||
"SELECT ?, test FROM test WHERE c1 = ?;"
|
"SELECT ?, test FROM test WHERE c1 = ?;"
|
||||||
"};"
|
"};"
|
||||||
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
||||||
"DEALLOCATE PREPARE stmt;";
|
"DEALLOCATE PREPARE stmt;";
|
||||||
|
|
||||||
TEST_PARSE_SQL_QUERY(query, result, 3);
|
TEST_PARSE_SQL_QUERY(query, result, 3);
|
||||||
|
|
||||||
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
|
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
|
||||||
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
|
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||||
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
||||||
|
|
||||||
// Prepare Statement #1
|
// Prepare Statement #1
|
||||||
ASSERT_STREQ(prep1->name, "test");
|
ASSERT_STREQ(prep1->name, "test");
|
||||||
ASSERT_EQ(prep1->placeholders.size(), 3);
|
ASSERT_EQ(prep1->placeholders.size(), 3);
|
||||||
ASSERT_EQ(prep1->query->size(), 2);
|
ASSERT_EQ(prep1->query->size(), 2);
|
||||||
|
|
||||||
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
||||||
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
||||||
|
|
||||||
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||||
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
||||||
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
||||||
|
|
||||||
// Check IDs of placeholders
|
// Check IDs of placeholders
|
||||||
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||||
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
||||||
|
|
||||||
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
||||||
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
||||||
|
|
||||||
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
||||||
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
||||||
|
|
||||||
// Prepare Statement #2
|
// Prepare Statement #2
|
||||||
ASSERT_STREQ(prep2->name, "stmt");
|
ASSERT_STREQ(prep2->name, "stmt");
|
||||||
ASSERT_EQ(prep2->placeholders.size(), 1);
|
ASSERT_EQ(prep2->placeholders.size(), 1);
|
||||||
|
|
||||||
// Deallocate Statement
|
// Deallocate Statement
|
||||||
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
||||||
ASSERT_STREQ(drop->name, "stmt");
|
ASSERT_STREQ(drop->name, "stmt");
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(ExecuteStatementTest) {
|
TEST(ExecuteStatementTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
|
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
|
||||||
|
|
||||||
ASSERT_STREQ(stmt->name, "test");
|
ASSERT_STREQ(stmt->name, "test");
|
||||||
ASSERT_EQ(stmt->parameters->size(), 2);
|
ASSERT_EQ(stmt->parameters->size(), 2);
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_MAIN();
|
TEST_MAIN();
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "thirdparty/microtest/microtest.h"
|
||||||
|
#include "sql_asserts.h"
|
||||||
|
#include "SQLParser.h"
|
||||||
|
#include "sqlhelper.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <streambuf>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace hsql;
|
||||||
|
|
||||||
|
TEST(TPCHQueryGrammarTests) {
|
||||||
|
std::vector<std::string> files = {
|
||||||
|
"test/queries/tpc-h-01.sql",
|
||||||
|
"test/queries/tpc-h-02.sql",
|
||||||
|
"test/queries/tpc-h-03.sql",
|
||||||
|
"test/queries/tpc-h-04.sql",
|
||||||
|
"test/queries/tpc-h-05.sql",
|
||||||
|
"test/queries/tpc-h-06.sql",
|
||||||
|
"test/queries/tpc-h-07.sql",
|
||||||
|
"test/queries/tpc-h-08.sql",
|
||||||
|
"test/queries/tpc-h-09.sql",
|
||||||
|
"test/queries/tpc-h-10.sql",
|
||||||
|
"test/queries/tpc-h-11-15.sql",
|
||||||
|
"test/queries/tpc-h-16-22.sql"
|
||||||
|
};
|
||||||
|
|
||||||
|
int testsFailed = 0;
|
||||||
|
for (const std::string& file_path : files) {
|
||||||
|
std::ifstream t(file_path.c_str());
|
||||||
|
std::string query((std::istreambuf_iterator<char>(t)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
SQLParserResult* result = SQLParser::parseSQLString(query.c_str());
|
||||||
|
if (!result->isValid()) {
|
||||||
|
mt::printFailed(file_path.c_str());
|
||||||
|
printf("%s %s (L%d:%d)%s\n", mt::red(), result->errorMsg(), result->errorLine(), result->errorColumn(), mt::def());
|
||||||
|
++testsFailed;
|
||||||
|
} else {
|
||||||
|
mt::printOk(file_path.c_str());
|
||||||
|
}
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
ASSERT_EQ(testsFailed, 0);
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ SELECT * FROM "table" LIMIT 10 OFFSET 10; SELECT * FROM second;
|
||||||
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
|
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
|
||||||
SELECT * FROM (SELECT * FROM t1);
|
SELECT * FROM (SELECT * FROM t1);
|
||||||
SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
|
SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
|
||||||
|
SELECT TOP 10 * FROM t1 ORDER BY col1, col2;
|
||||||
|
SELECT a, MAX(b), MAX(c, d), CUSTOM(q, UP(r)) AS f FROM t1;
|
||||||
|
SELECT * FROM t WHERE a BETWEEN 1 and c;
|
||||||
# JOIN
|
# JOIN
|
||||||
SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5
|
SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5
|
||||||
SELECT * FROM t1 JOIN t2 ON c1 = c2;
|
SELECT * FROM t1 JOIN t2 ON c1 = c2;
|
||||||
|
|
Loading…
Reference in New Issue