commit
353e25ae00
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
|||
TESTCPP = $(shell find test/ -name '*.cpp')
|
||||
|
||||
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
||||
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
|
||||
ALLTEST = $(shell find test/ -name '*.cpp') $(shell find test/ -name '*.h')
|
||||
|
||||
# compile & link flages
|
||||
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::UpdateClause*>* update_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 ($$);
|
||||
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec>
|
||||
} <str_vec> <table_vec> <column_vec> <update_vec> <expr_vec> <order_vec>
|
||||
%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 TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
||||
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
||||
%token OUTER RIGHT TABLE UNION USING WHERE CALL DATE DESC
|
||||
%token DROP FILE FROM FULL HASH HINT INTO JOIN LEFT LIKE
|
||||
%token LOAD NULL PART PLAN SHOW TEXT TIME VIEW WITH ADD ALL
|
||||
%token AND ASC CSV FOR INT KEY NOT OFF SET TBL TOP AS BY IF
|
||||
%token IN IS OF ON OR TO
|
||||
|
||||
%token OUTER RIGHT TABLE UNION USING WHERE CALL CASE DATE
|
||||
%token DESC DROP ELSE FILE FROM FULL HASH HINT INTO JOIN
|
||||
%token LEFT LIKE LOAD NULL PART PLAN SHOW TEXT THEN TIME
|
||||
%token VIEW WHEN WITH ADD ALL AND ASC CSV END FOR INT KEY
|
||||
%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)
|
||||
|
@ -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 <table> from_clause table_ref table_ref_atomic table_ref_name
|
||||
%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> comp_expr opt_where join_condition opt_having
|
||||
%type <order> opt_order
|
||||
%type <limit> opt_limit
|
||||
%type <expr> comp_expr opt_where join_condition opt_having case_expr in_expr
|
||||
%type <limit> opt_limit opt_top
|
||||
%type <order> order_desc
|
||||
%type <order_type> opt_order_type
|
||||
%type <column_t> column_def
|
||||
%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 <expr_vec> expr_list select_list literal_list
|
||||
%type <table_vec> table_ref_commalist
|
||||
%type <order_vec> opt_order order_list
|
||||
%type <update_vec> update_clause_commalist
|
||||
%type <column_vec> column_def_commalist
|
||||
|
||||
|
@ -476,7 +478,12 @@ select_no_paren:
|
|||
select_clause opt_order opt_limit {
|
||||
$$ = $1;
|
||||
$$->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 {
|
||||
// TODO: allow multiple unions (through linked list)
|
||||
|
@ -485,13 +492,23 @@ select_no_paren:
|
|||
$$ = $1;
|
||||
$$->unionSelect = $3;
|
||||
$$->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 {
|
||||
$$ = $1;
|
||||
$$->unionSelect = $3;
|
||||
$$->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 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();
|
||||
$$->selectDistinct = $2;
|
||||
$$->selectList = $3;
|
||||
$$->fromTable = $4;
|
||||
$$->whereClause = $5;
|
||||
$$->groupBy = $6;
|
||||
$$->limit = $2;
|
||||
$$->selectDistinct = $3;
|
||||
$$->selectList = $4;
|
||||
$$->fromTable = $5;
|
||||
$$->whereClause = $6;
|
||||
$$->groupBy = $7;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -521,7 +539,6 @@ select_list:
|
|||
expr_list
|
||||
;
|
||||
|
||||
|
||||
from_clause:
|
||||
FROM table_ref { $$ = $2; }
|
||||
;
|
||||
|
@ -546,16 +563,31 @@ opt_having:
|
|||
| /* empty */ { $$ = NULL; }
|
||||
|
||||
opt_order:
|
||||
ORDER BY expr opt_order_type { $$ = new OrderDescription($4, $3); }
|
||||
ORDER BY order_list { $$ = $3; }
|
||||
| /* 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:
|
||||
ASC { $$ = kOrderAsc; }
|
||||
| DESC { $$ = kOrderDesc; }
|
||||
| /* 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:
|
||||
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
||||
|
@ -584,11 +616,21 @@ expr_alias:
|
|||
;
|
||||
|
||||
expr:
|
||||
operand
|
||||
| between_expr
|
||||
| logic_expr
|
||||
| exists_expr
|
||||
| case_expr
|
||||
| in_expr
|
||||
;
|
||||
|
||||
operand:
|
||||
'(' expr ')' { $$ = $2; }
|
||||
| scalar_expr
|
||||
| unary_expr
|
||||
| binary_expr
|
||||
| function_expr
|
||||
| '(' select_no_paren ')' { $$ = Expr::makeSelect($2); }
|
||||
;
|
||||
|
||||
scalar_expr:
|
||||
|
@ -598,36 +640,59 @@ scalar_expr:
|
|||
;
|
||||
|
||||
unary_expr:
|
||||
'-' expr { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); }
|
||||
| NOT expr { $$ = Expr::makeOpUnary(Expr::NOT, $2); }
|
||||
'-' operand { $$ = Expr::makeOpUnary(Expr::UMINUS, $2); }
|
||||
| NOT operand { $$ = Expr::makeOpUnary(Expr::NOT, $2); }
|
||||
;
|
||||
|
||||
binary_expr:
|
||||
comp_expr
|
||||
| expr '-' expr { $$ = Expr::makeOpBinary($1, '-', $3); }
|
||||
| expr '+' expr { $$ = Expr::makeOpBinary($1, '+', $3); }
|
||||
| expr '/' expr { $$ = Expr::makeOpBinary($1, '/', $3); }
|
||||
| expr '*' expr { $$ = Expr::makeOpBinary($1, '*', $3); }
|
||||
| expr '%' expr { $$ = Expr::makeOpBinary($1, '%', $3); }
|
||||
| expr '^' expr { $$ = Expr::makeOpBinary($1, '^', $3); }
|
||||
| expr AND expr { $$ = Expr::makeOpBinary($1, Expr::AND, $3); }
|
||||
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
||||
| expr LIKE expr { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); }
|
||||
| expr NOT LIKE expr { $$ = Expr::makeOpBinary($1, Expr::NOT_LIKE, $4); }
|
||||
| operand '-' operand { $$ = Expr::makeOpBinary($1, '-', $3); }
|
||||
| operand '+' operand { $$ = Expr::makeOpBinary($1, '+', $3); }
|
||||
| operand '/' operand { $$ = Expr::makeOpBinary($1, '/', $3); }
|
||||
| operand '*' operand { $$ = Expr::makeOpBinary($1, '*', $3); }
|
||||
| operand '%' operand { $$ = Expr::makeOpBinary($1, '%', $3); }
|
||||
| operand '^' operand { $$ = Expr::makeOpBinary($1, '^', $3); }
|
||||
| operand LIKE operand { $$ = Expr::makeOpBinary($1, Expr::LIKE, $3); }
|
||||
| operand NOT LIKE operand { $$ = 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:
|
||||
expr '=' expr { $$ = Expr::makeOpBinary($1, '=', $3); }
|
||||
| expr NOTEQUALS expr { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }
|
||||
| expr '<' expr { $$ = Expr::makeOpBinary($1, '<', $3); }
|
||||
| expr '>' expr { $$ = Expr::makeOpBinary($1, '>', $3); }
|
||||
| expr LESSEQ expr { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); }
|
||||
| expr GREATEREQ expr { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); }
|
||||
operand '=' operand { $$ = Expr::makeOpBinary($1, '=', $3); }
|
||||
| operand NOTEQUALS operand { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }
|
||||
| operand '<' operand { $$ = Expr::makeOpBinary($1, '<', $3); }
|
||||
| operand '>' operand { $$ = Expr::makeOpBinary($1, '>', $3); }
|
||||
| operand LESSEQ operand { $$ = Expr::makeOpBinary($1, Expr::LESS_EQ, $3); }
|
||||
| operand GREATEREQ operand { $$ = Expr::makeOpBinary($1, Expr::GREATER_EQ, $3); }
|
||||
;
|
||||
|
||||
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:
|
||||
|
@ -659,7 +724,6 @@ star_expr:
|
|||
'*' { $$ = new Expr(kExprStar); }
|
||||
;
|
||||
|
||||
|
||||
placeholder_expr:
|
||||
'?' {
|
||||
$$ = Expr::makePlaceholder(yylloc.total_column);
|
||||
|
@ -751,11 +815,15 @@ join_clause:
|
|||
;
|
||||
|
||||
opt_join_type:
|
||||
INNER { $$ = kJoinInner; }
|
||||
| OUTER { $$ = kJoinOuter; }
|
||||
| LEFT { $$ = kJoinLeft; }
|
||||
| RIGHT { $$ = kJoinRight; }
|
||||
| /* empty, default */ { $$ = kJoinInner; }
|
||||
INNER { $$ = kJoinInner; }
|
||||
| OUTER { $$ = kJoinOuter; }
|
||||
| LEFT OUTER { $$ = kJoinLeftOuter; }
|
||||
| RIGHT OUTER { $$ = kJoinRightOuter; }
|
||||
| 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 BEGIN(INITIAL);
|
||||
|
||||
|
||||
[ \t\n]+ /* skip whitespace */;
|
||||
|
||||
|
||||
|
||||
DEALLOCATE TOKEN(DEALLOCATE)
|
||||
PARAMETERS TOKEN(PARAMETERS)
|
||||
INTERSECT TOKEN(INTERSECT)
|
||||
|
@ -127,9 +124,11 @@ UNION TOKEN(UNION)
|
|||
USING TOKEN(USING)
|
||||
WHERE TOKEN(WHERE)
|
||||
CALL TOKEN(CALL)
|
||||
CASE TOKEN(CASE)
|
||||
DATE TOKEN(DATE)
|
||||
DESC TOKEN(DESC)
|
||||
DROP TOKEN(DROP)
|
||||
ELSE TOKEN(ELSE)
|
||||
FILE TOKEN(FILE)
|
||||
FROM TOKEN(FROM)
|
||||
FULL TOKEN(FULL)
|
||||
|
@ -145,14 +144,17 @@ PART TOKEN(PART)
|
|||
PLAN TOKEN(PLAN)
|
||||
SHOW TOKEN(SHOW)
|
||||
TEXT TOKEN(TEXT)
|
||||
THEN TOKEN(THEN)
|
||||
TIME TOKEN(TIME)
|
||||
VIEW TOKEN(VIEW)
|
||||
WHEN TOKEN(WHEN)
|
||||
WITH TOKEN(WITH)
|
||||
ADD TOKEN(ADD)
|
||||
ALL TOKEN(ALL)
|
||||
AND TOKEN(AND)
|
||||
ASC TOKEN(ASC)
|
||||
CSV TOKEN(CSV)
|
||||
END TOKEN(END)
|
||||
FOR TOKEN(FOR)
|
||||
INT TOKEN(INT)
|
||||
KEY TOKEN(KEY)
|
||||
|
@ -171,15 +173,12 @@ ON TOKEN(ON)
|
|||
OR TOKEN(OR)
|
||||
TO TOKEN(TO)
|
||||
|
||||
|
||||
"<>" TOKEN(NOTEQUALS)
|
||||
"<=" TOKEN(LESSEQ)
|
||||
">=" TOKEN(GREATEREQ)
|
||||
|
||||
|
||||
[-+*/(){},.;<>=^%:?] { return yytext[0]; }
|
||||
|
||||
|
||||
[0-9]+"."[0-9]* |
|
||||
"."[0-9]* {
|
||||
yylval->fval = atof(yytext);
|
||||
|
@ -202,7 +201,6 @@ TO TOKEN(TO)
|
|||
return SQL_IDENTIFIER;
|
||||
}
|
||||
|
||||
|
||||
'[^'\n]*' {
|
||||
// Crop the leading and trailing quote char
|
||||
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
||||
|
|
|
@ -140,6 +140,11 @@ IS
|
|||
ISNULL
|
||||
BETWEEN
|
||||
ESCAPE
|
||||
CASE
|
||||
WHEN
|
||||
THEN
|
||||
ELSE
|
||||
END
|
||||
|
||||
// With
|
||||
WITH
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Expr.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
|
@ -9,6 +10,8 @@ namespace hsql {
|
|||
type(type),
|
||||
expr(NULL),
|
||||
expr2(NULL),
|
||||
exprList(NULL),
|
||||
select(NULL),
|
||||
name(NULL),
|
||||
table(NULL),
|
||||
alias(NULL) {};
|
||||
|
@ -16,9 +19,17 @@ namespace hsql {
|
|||
Expr::~Expr() {
|
||||
delete expr;
|
||||
delete expr2;
|
||||
delete select;
|
||||
free(name);
|
||||
free(table);
|
||||
free(alias);
|
||||
|
||||
if (exprList != NULL) {
|
||||
for (Expr* e : *exprList) {
|
||||
delete e;
|
||||
}
|
||||
delete exprList;
|
||||
}
|
||||
}
|
||||
|
||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||
|
@ -47,6 +58,26 @@ namespace hsql {
|
|||
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* e = new Expr(kExprLiteralInt);
|
||||
e->ival = val;
|
||||
|
@ -79,10 +110,10 @@ namespace hsql {
|
|||
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);
|
||||
e->name = func_name;
|
||||
e->expr = expr;
|
||||
e->exprList = exprList;
|
||||
e->distinct = distinct;
|
||||
return e;
|
||||
}
|
||||
|
@ -93,6 +124,37 @@ namespace hsql {
|
|||
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) {
|
||||
return e_type == type;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace hsql {
|
||||
class SelectStatement;
|
||||
|
||||
// Helper function used by the lexer.
|
||||
// TODO: move to more appropriate place.
|
||||
|
@ -18,7 +20,8 @@ namespace hsql {
|
|||
kExprPlaceholder,
|
||||
kExprColumnRef,
|
||||
kExprFunctionRef,
|
||||
kExprOperator
|
||||
kExprOperator,
|
||||
kExprSelect
|
||||
};
|
||||
|
||||
typedef struct Expr Expr;
|
||||
|
@ -31,9 +34,14 @@ namespace hsql {
|
|||
// + - * / < > = %
|
||||
// Non-trivial are: <> <= >= LIKE ISNULL NOT
|
||||
enum OperatorType {
|
||||
SIMPLE_OP,
|
||||
NONE,
|
||||
|
||||
// Ternary operators
|
||||
BETWEEN,
|
||||
CASE,
|
||||
|
||||
// Binary operators.
|
||||
SIMPLE_OP,
|
||||
NOT_EQUALS,
|
||||
LESS_EQ,
|
||||
GREATER_EQ,
|
||||
|
@ -41,11 +49,13 @@ namespace hsql {
|
|||
NOT_LIKE,
|
||||
AND,
|
||||
OR,
|
||||
IN,
|
||||
|
||||
// Unary operators.
|
||||
NOT,
|
||||
UMINUS,
|
||||
ISNULL
|
||||
ISNULL,
|
||||
EXISTS
|
||||
};
|
||||
|
||||
|
||||
|
@ -59,8 +69,11 @@ namespace hsql {
|
|||
|
||||
ExprType type;
|
||||
|
||||
// TODO: Replace expressions by list.
|
||||
Expr* expr;
|
||||
Expr* expr2;
|
||||
std::vector<Expr*>* exprList;
|
||||
SelectStatement* select;
|
||||
char* name;
|
||||
char* table;
|
||||
char* alias;
|
||||
|
@ -72,6 +85,7 @@ namespace hsql {
|
|||
char opChar;
|
||||
bool distinct;
|
||||
|
||||
|
||||
// Convenience accessor methods.
|
||||
|
||||
bool isType(ExprType e_type);
|
||||
|
@ -97,6 +111,10 @@ namespace hsql {
|
|||
|
||||
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(double val);
|
||||
|
@ -107,9 +125,17 @@ namespace hsql {
|
|||
|
||||
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* 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
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace hsql {
|
|||
GroupByDescription* groupBy;
|
||||
|
||||
SelectStatement* unionSelect;
|
||||
OrderDescription* order;
|
||||
std::vector<OrderDescription*>* order;
|
||||
LimitDescription* limit;
|
||||
};
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ namespace hsql {
|
|||
kJoinOuter,
|
||||
kJoinLeft,
|
||||
kJoinRight,
|
||||
kJoinLeftOuter,
|
||||
kJoinRightOuter,
|
||||
kJoinCross,
|
||||
kJoinNatural
|
||||
};
|
||||
|
||||
// Definition of a join construct.
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace hsql {
|
|||
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); });
|
||||
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;
|
||||
|
@ -193,7 +193,6 @@ namespace hsql {
|
|||
delete whereClause;
|
||||
delete groupBy;
|
||||
delete unionSelect;
|
||||
delete order;
|
||||
delete limit;
|
||||
|
||||
// Delete each element in the select list.
|
||||
|
@ -203,6 +202,13 @@ namespace hsql {
|
|||
}
|
||||
delete selectList;
|
||||
}
|
||||
|
||||
if (order != NULL) {
|
||||
for (OrderDescription* desc : *order) {
|
||||
delete desc;
|
||||
}
|
||||
delete order;
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStatement
|
||||
|
|
|
@ -139,8 +139,8 @@ namespace hsql {
|
|||
|
||||
if (stmt->order != NULL) {
|
||||
inprint("OrderBy:", numIndent + 1);
|
||||
printExpression(stmt->order->expr, numIndent + 2);
|
||||
if (stmt->order->type == kOrderAsc) inprint("ascending", numIndent + 2);
|
||||
printExpression(stmt->order->at(0)->expr, numIndent + 2);
|
||||
if (stmt->order->at(0)->type == kOrderAsc) inprint("ascending", 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;
|
||||
}
|
||||
|
||||
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_PARSE_SINGLE_SQL(
|
||||
|
@ -46,7 +85,7 @@ TEST(SelectDistinctTest) {
|
|||
TEST_PARSE_SINGLE_SQL(
|
||||
"SELECT DISTINCT grade, city FROM students;",
|
||||
kStmtSelect,
|
||||
SelectStatement,
|
||||
SelectStatement,
|
||||
result,
|
||||
stmt);
|
||||
|
||||
|
@ -72,4 +111,115 @@ TEST(SelectGroupDistinctTest) {
|
|||
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::ifstream infile(path);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
std::istringstream iss(line);
|
||||
std::ifstream infile(path);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
std::istringstream iss(line);
|
||||
|
||||
// Skip comments
|
||||
if (line[0] == '#' ||
|
||||
(line[0] == '-' && line[1] == '-')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.push_back(line);
|
||||
// Skip comments
|
||||
if (line[0] == '#' ||
|
||||
(line[0] == '-' && line[1] == '-')) {
|
||||
continue;
|
||||
}
|
||||
return lines;
|
||||
|
||||
lines.push_back(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
||||
|
||||
TEST(AutoGrammarTest) {
|
||||
const std::vector<std::string>& args = mt::Runtime::args();
|
||||
if (args.size() <= 1) {
|
||||
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
||||
return;
|
||||
}
|
||||
const std::vector<std::string>& args = mt::Runtime::args();
|
||||
if (args.size() <= 1) {
|
||||
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool globalExpectFalse = false;
|
||||
bool useFile = false;
|
||||
std::string filePath = "";
|
||||
|
||||
// Parse command line arguments
|
||||
uint i = 1;
|
||||
for (; i < args.size(); ++i) {
|
||||
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
||||
else if (STREQ(args[i], "-f")) {
|
||||
useFile = true;
|
||||
filePath = args[++i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool globalExpectFalse = false;
|
||||
bool useFile = false;
|
||||
std::string filePath = "";
|
||||
|
||||
|
||||
// Read list of queries for this rest
|
||||
std::vector<std::string> queries;
|
||||
if (useFile) {
|
||||
queries = readlines(filePath);
|
||||
// Parse command line arguments
|
||||
uint i = 1;
|
||||
for (; i < args.size(); ++i) {
|
||||
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
||||
else if (STREQ(args[i], "-f")) {
|
||||
useFile = true;
|
||||
filePath = args[++i];
|
||||
} 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
|
||||
int numFailed = 0;
|
||||
for (std::string sql : queries) {
|
||||
bool expectFalse = globalExpectFalse;
|
||||
if (sql.at(0) == '!') {
|
||||
expectFalse = !expectFalse;
|
||||
sql = sql.substr(1);
|
||||
}
|
||||
// Parsing
|
||||
SQLParserResult* result = SQLParser::parseSQLString(sql.c_str());
|
||||
|
||||
// Measuring the parsing time
|
||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||
start = std::chrono::system_clock::now();
|
||||
end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = end - start;
|
||||
double us = elapsed_seconds.count() * 1000 * 1000;
|
||||
|
||||
// Parsing
|
||||
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 == 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());
|
||||
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 {
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
|
||||
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->expr);
|
||||
ASSERT(stmt->expr->isType(kExprOperator));
|
||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||
ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
|
||||
const DeleteStatement* stmt = (const DeleteStatement*) result->getStatement(0);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->expr);
|
||||
ASSERT(stmt->expr->isType(kExprOperator));
|
||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||
ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
|
||||
|
||||
delete result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST(CreateStatementTest) {
|
||||
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);
|
||||
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);
|
||||
|
||||
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0);
|
||||
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->columns);
|
||||
ASSERT_EQ(stmt->columns->size(), 4);
|
||||
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
||||
ASSERT_STREQ(stmt->columns->at(1)->name, "student_number");
|
||||
ASSERT_STREQ(stmt->columns->at(2)->name, "city");
|
||||
ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
|
||||
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
|
||||
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
|
||||
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
|
||||
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
|
||||
const CreateStatement* stmt = (const CreateStatement*) result->getStatement(0);
|
||||
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->columns);
|
||||
ASSERT_EQ(stmt->columns->size(), 4);
|
||||
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
||||
ASSERT_STREQ(stmt->columns->at(1)->name, "student_number");
|
||||
ASSERT_STREQ(stmt->columns->at(2)->name, "city");
|
||||
ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
|
||||
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
|
||||
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
|
||||
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
|
||||
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
|
||||
|
||||
delete result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
TEST(UpdateStatementTest) {
|
||||
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);
|
||||
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);
|
||||
|
||||
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0);
|
||||
ASSERT_NOTNULL(stmt->table);
|
||||
ASSERT_STREQ(stmt->table->name, "students");
|
||||
|
||||
ASSERT_NOTNULL(stmt->updates);
|
||||
ASSERT_EQ(stmt->updates->size(), 2);
|
||||
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
|
||||
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
|
||||
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
|
||||
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
|
||||
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
|
||||
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
|
||||
const UpdateStatement* stmt = (const UpdateStatement*) result->getStatement(0);
|
||||
ASSERT_NOTNULL(stmt->table);
|
||||
ASSERT_STREQ(stmt->table->name, "students");
|
||||
|
||||
ASSERT_NOTNULL(stmt->where);
|
||||
ASSERT(stmt->where->isType(kExprOperator));
|
||||
ASSERT(stmt->where->isSimpleOp('='));
|
||||
ASSERT_STREQ(stmt->where->expr->name, "name");
|
||||
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");\
|
||||
ASSERT_NOTNULL(stmt->updates);
|
||||
ASSERT_EQ(stmt->updates->size(), 2);
|
||||
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
|
||||
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
|
||||
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
|
||||
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
|
||||
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
|
||||
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
|
||||
|
||||
delete result;
|
||||
ASSERT_NOTNULL(stmt->where);
|
||||
ASSERT(stmt->where->isType(kExprOperator));
|
||||
ASSERT(stmt->where->isSimpleOp('='));
|
||||
ASSERT_STREQ(stmt->where->expr->name, "name");
|
||||
ASSERT_STREQ(stmt->where->expr2->name, "Max Mustermann");
|
||||
\
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
TEST(InsertStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
|
||||
kStmtInsert,
|
||||
InsertStatement,
|
||||
result,
|
||||
stmt);
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
|
||||
kStmtInsert,
|
||||
InsertStatement,
|
||||
result,
|
||||
stmt);
|
||||
|
||||
ASSERT_EQ(stmt->values->size(), 4);
|
||||
// TODO
|
||||
ASSERT_EQ(stmt->values->size(), 4);
|
||||
// TODO
|
||||
|
||||
delete result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
TEST(DropTableStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"DROP TABLE students",
|
||||
kStmtDrop,
|
||||
DropStatement,
|
||||
result,
|
||||
stmt);
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"DROP TABLE students",
|
||||
kStmtDrop,
|
||||
DropStatement,
|
||||
result,
|
||||
stmt);
|
||||
|
||||
ASSERT_EQ(stmt->type, DropStatement::kTable);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
ASSERT_EQ(stmt->type, DropStatement::kTable);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
|
||||
delete result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
TEST(PrepareStatementTest) {
|
||||
std::string query = "PREPARE test {"
|
||||
"INSERT INTO test VALUES(?);"
|
||||
"SELECT ?, test FROM test WHERE c1 = ?;"
|
||||
"};"
|
||||
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
||||
"DEALLOCATE PREPARE stmt;";
|
||||
std::string query = "PREPARE test {"
|
||||
"INSERT INTO test VALUES(?);"
|
||||
"SELECT ?, test FROM test WHERE c1 = ?;"
|
||||
"};"
|
||||
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
||||
"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, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
||||
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
|
||||
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
||||
|
||||
// Prepare Statement #1
|
||||
ASSERT_STREQ(prep1->name, "test");
|
||||
ASSERT_EQ(prep1->placeholders.size(), 3);
|
||||
ASSERT_EQ(prep1->query->size(), 2);
|
||||
|
||||
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
||||
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
||||
// Prepare Statement #1
|
||||
ASSERT_STREQ(prep1->name, "test");
|
||||
ASSERT_EQ(prep1->placeholders.size(), 3);
|
||||
ASSERT_EQ(prep1->query->size(), 2);
|
||||
|
||||
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
||||
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
||||
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
||||
|
||||
// Check IDs of placeholders
|
||||
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
||||
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
||||
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
||||
|
||||
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
||||
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
||||
// Check IDs of placeholders
|
||||
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
||||
|
||||
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
||||
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
||||
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
||||
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
||||
|
||||
// Prepare Statement #2
|
||||
ASSERT_STREQ(prep2->name, "stmt");
|
||||
ASSERT_EQ(prep2->placeholders.size(), 1);
|
||||
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
||||
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
||||
|
||||
// Deallocate Statement
|
||||
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
||||
ASSERT_STREQ(drop->name, "stmt");
|
||||
// Prepare Statement #2
|
||||
ASSERT_STREQ(prep2->name, "stmt");
|
||||
ASSERT_EQ(prep2->placeholders.size(), 1);
|
||||
|
||||
delete result;
|
||||
// Deallocate Statement
|
||||
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
|
||||
ASSERT_STREQ(drop->name, "stmt");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
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_EQ(stmt->parameters->size(), 2);
|
||||
ASSERT_STREQ(stmt->name, "test");
|
||||
ASSERT_EQ(stmt->parameters->size(), 2);
|
||||
|
||||
delete result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
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 (SELECT * FROM t1);
|
||||
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
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue