Merge pull request #29 from torpedro/tpch-tests

TPC-H Capabilities
This commit is contained in:
Pedro Flemming 2017-03-08 17:09:21 +01:00 committed by GitHub
commit 353e25ae00
28 changed files with 1394 additions and 793 deletions

View File

@ -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

View File

@ -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; }
;

View File

@ -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);

View File

@ -140,6 +140,11 @@ IS
ISNULL
BETWEEN
ESCAPE
CASE
WHEN
THEN
ELSE
END
// With
WITH

View File

@ -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;
}

View File

@ -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

View File

@ -63,7 +63,7 @@ namespace hsql {
GroupByDescription* groupBy;
SelectStatement* unionSelect;
OrderDescription* order;
std::vector<OrderDescription*>* order;
LimitDescription* limit;
};

View File

@ -47,6 +47,10 @@ namespace hsql {
kJoinOuter,
kJoinLeft,
kJoinRight,
kJoinLeftOuter,
kJoinRightOuter,
kJoinCross,
kJoinNatural
};
// Definition of a join construct.

View File

@ -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

View File

@ -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);
}

View File

@ -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

10
test/queries/tpc-h-02.sql Normal file
View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

11
test/queries/tpc-h-07.sql Normal file
View File

@ -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

10
test/queries/tpc-h-08.sql Normal file
View File

@ -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

10
test/queries/tpc-h-09.sql Normal file
View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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(
@ -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;
}

View File

@ -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 = "";
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;
}
}
// 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);
}

View File

@ -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");
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");
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");
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->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;
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);
// 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);
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
// Check IDs of placeholders
ASSERT_EQ(insert->values->at(0)->ival, 0);
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
// Check IDs of placeholders
ASSERT_EQ(insert->values->at(0)->ival, 0);
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
ASSERT_EQ(select->selectList->at(0)->ival, 1);
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
ASSERT_EQ(select->selectList->at(0)->ival, 1);
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
ASSERT_EQ(select->whereClause->expr2->ival, 2);
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
ASSERT_EQ(select->whereClause->expr2->ival, 2);
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
// Prepare Statement #2
ASSERT_STREQ(prep2->name, "stmt");
ASSERT_EQ(prep2->placeholders.size(), 1);
// Prepare Statement #2
ASSERT_STREQ(prep2->name, "stmt");
ASSERT_EQ(prep2->placeholders.size(), 1);
// Deallocate Statement
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
ASSERT_STREQ(drop->name, "stmt");
// Deallocate Statement
ASSERT_EQ(drop->type, DropStatement::kPreparedStatement);
ASSERT_STREQ(drop->name, "stmt");
delete result;
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();

46
test/tpc_h_tests.cpp Normal file
View File

@ -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);
}

View File

@ -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;