implement CASE WHEN expressions
This commit is contained in:
parent
5605dbab7e
commit
b7828e698e
|
@ -169,12 +169,11 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
|
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
|
||||||
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
|
||||||
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
%token DELTA GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
|
||||||
%token OUTER RIGHT TABLE UNION USING WHERE CALL DATE DESC
|
%token OUTER RIGHT TABLE UNION USING WHERE CALL CASE DATE
|
||||||
%token DROP FILE FROM FULL HASH HINT INTO JOIN LEFT LIKE
|
%token DESC DROP ELSE FILE FROM FULL HASH HINT INTO JOIN
|
||||||
%token LOAD NULL PART PLAN SHOW TEXT TIME VIEW WITH ADD ALL
|
%token LEFT LIKE LOAD NULL PART PLAN SHOW TEXT THEN TIME
|
||||||
%token AND ASC CSV FOR INT KEY NOT OFF SET TBL TOP AS BY IF
|
%token VIEW WHEN WITH ADD ALL AND ASC CSV END FOR INT KEY
|
||||||
%token IN IS OF ON OR TO
|
%token NOT OFF SET TBL TOP AS BY IF IN IS OF ON OR TO
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
||||||
|
@ -198,7 +197,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const ch
|
||||||
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
|
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
|
||||||
%type <expr> function_expr between_expr star_expr expr_alias placeholder_expr
|
%type <expr> function_expr between_expr star_expr expr_alias placeholder_expr
|
||||||
%type <expr> column_name literal int_literal num_literal string_literal
|
%type <expr> column_name literal int_literal num_literal string_literal
|
||||||
%type <expr> comp_expr opt_where join_condition opt_having
|
%type <expr> comp_expr opt_where join_condition opt_having case_expr
|
||||||
%type <limit> opt_limit opt_top
|
%type <limit> opt_limit opt_top
|
||||||
%type <order> order_desc
|
%type <order> order_desc
|
||||||
%type <order_type> opt_order_type
|
%type <order_type> opt_order_type
|
||||||
|
@ -606,6 +605,7 @@ expr:
|
||||||
| between_expr
|
| between_expr
|
||||||
| logic_expr
|
| logic_expr
|
||||||
| exists_expr
|
| exists_expr
|
||||||
|
| case_expr
|
||||||
;
|
;
|
||||||
|
|
||||||
operand:
|
operand:
|
||||||
|
@ -645,6 +645,11 @@ logic_expr:
|
||||||
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// TODO: allow no else specified
|
||||||
|
case_expr:
|
||||||
|
CASE WHEN operand THEN operand ELSE operand END { $$ = Expr::makeCase($3, $5, $7); }
|
||||||
|
;
|
||||||
|
|
||||||
exists_expr:
|
exists_expr:
|
||||||
EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); }
|
EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); }
|
||||||
;
|
;
|
||||||
|
|
|
@ -54,11 +54,8 @@
|
||||||
<COMMENT>[^\n]* /* skipping comment content until a end of line is read */;
|
<COMMENT>[^\n]* /* skipping comment content until a end of line is read */;
|
||||||
<COMMENT>\n BEGIN(INITIAL);
|
<COMMENT>\n BEGIN(INITIAL);
|
||||||
|
|
||||||
|
|
||||||
[ \t\n]+ /* skip whitespace */;
|
[ \t\n]+ /* skip whitespace */;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DEALLOCATE TOKEN(DEALLOCATE)
|
DEALLOCATE TOKEN(DEALLOCATE)
|
||||||
PARAMETERS TOKEN(PARAMETERS)
|
PARAMETERS TOKEN(PARAMETERS)
|
||||||
INTERSECT TOKEN(INTERSECT)
|
INTERSECT TOKEN(INTERSECT)
|
||||||
|
@ -127,9 +124,11 @@ UNION TOKEN(UNION)
|
||||||
USING TOKEN(USING)
|
USING TOKEN(USING)
|
||||||
WHERE TOKEN(WHERE)
|
WHERE TOKEN(WHERE)
|
||||||
CALL TOKEN(CALL)
|
CALL TOKEN(CALL)
|
||||||
|
CASE TOKEN(CASE)
|
||||||
DATE TOKEN(DATE)
|
DATE TOKEN(DATE)
|
||||||
DESC TOKEN(DESC)
|
DESC TOKEN(DESC)
|
||||||
DROP TOKEN(DROP)
|
DROP TOKEN(DROP)
|
||||||
|
ELSE TOKEN(ELSE)
|
||||||
FILE TOKEN(FILE)
|
FILE TOKEN(FILE)
|
||||||
FROM TOKEN(FROM)
|
FROM TOKEN(FROM)
|
||||||
FULL TOKEN(FULL)
|
FULL TOKEN(FULL)
|
||||||
|
@ -145,14 +144,17 @@ PART TOKEN(PART)
|
||||||
PLAN TOKEN(PLAN)
|
PLAN TOKEN(PLAN)
|
||||||
SHOW TOKEN(SHOW)
|
SHOW TOKEN(SHOW)
|
||||||
TEXT TOKEN(TEXT)
|
TEXT TOKEN(TEXT)
|
||||||
|
THEN TOKEN(THEN)
|
||||||
TIME TOKEN(TIME)
|
TIME TOKEN(TIME)
|
||||||
VIEW TOKEN(VIEW)
|
VIEW TOKEN(VIEW)
|
||||||
|
WHEN TOKEN(WHEN)
|
||||||
WITH TOKEN(WITH)
|
WITH TOKEN(WITH)
|
||||||
ADD TOKEN(ADD)
|
ADD TOKEN(ADD)
|
||||||
ALL TOKEN(ALL)
|
ALL TOKEN(ALL)
|
||||||
AND TOKEN(AND)
|
AND TOKEN(AND)
|
||||||
ASC TOKEN(ASC)
|
ASC TOKEN(ASC)
|
||||||
CSV TOKEN(CSV)
|
CSV TOKEN(CSV)
|
||||||
|
END TOKEN(END)
|
||||||
FOR TOKEN(FOR)
|
FOR TOKEN(FOR)
|
||||||
INT TOKEN(INT)
|
INT TOKEN(INT)
|
||||||
KEY TOKEN(KEY)
|
KEY TOKEN(KEY)
|
||||||
|
@ -171,15 +173,12 @@ ON TOKEN(ON)
|
||||||
OR TOKEN(OR)
|
OR TOKEN(OR)
|
||||||
TO TOKEN(TO)
|
TO TOKEN(TO)
|
||||||
|
|
||||||
|
|
||||||
"<>" TOKEN(NOTEQUALS)
|
"<>" TOKEN(NOTEQUALS)
|
||||||
"<=" TOKEN(LESSEQ)
|
"<=" TOKEN(LESSEQ)
|
||||||
">=" TOKEN(GREATEREQ)
|
">=" TOKEN(GREATEREQ)
|
||||||
|
|
||||||
|
|
||||||
[-+*/(){},.;<>=^%:?] { return yytext[0]; }
|
[-+*/(){},.;<>=^%:?] { return yytext[0]; }
|
||||||
|
|
||||||
|
|
||||||
[0-9]+"."[0-9]* |
|
[0-9]+"."[0-9]* |
|
||||||
"."[0-9]* {
|
"."[0-9]* {
|
||||||
yylval->fval = atof(yytext);
|
yylval->fval = atof(yytext);
|
||||||
|
@ -202,7 +201,6 @@ TO TOKEN(TO)
|
||||||
return SQL_IDENTIFIER;
|
return SQL_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
'[^'\n]*' {
|
'[^'\n]*' {
|
||||||
// Crop the leading and trailing quote char
|
// Crop the leading and trailing quote char
|
||||||
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
||||||
|
|
|
@ -140,6 +140,11 @@ IS
|
||||||
ISNULL
|
ISNULL
|
||||||
BETWEEN
|
BETWEEN
|
||||||
ESCAPE
|
ESCAPE
|
||||||
|
CASE
|
||||||
|
WHEN
|
||||||
|
THEN
|
||||||
|
ELSE
|
||||||
|
END
|
||||||
|
|
||||||
// With
|
// With
|
||||||
WITH
|
WITH
|
||||||
|
|
|
@ -57,6 +57,16 @@ namespace hsql {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr* Expr::makeCase(Expr* expr, Expr* then, Expr* other) {
|
||||||
|
Expr* e = new Expr(kExprOperator);
|
||||||
|
e->expr = expr;
|
||||||
|
e->opType = CASE;
|
||||||
|
e->exprList = new std::vector<Expr*>();
|
||||||
|
e->exprList->push_back(then);
|
||||||
|
e->exprList->push_back(other);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
Expr* Expr::makeLiteral(int64_t val) {
|
Expr* Expr::makeLiteral(int64_t val) {
|
||||||
Expr* e = new Expr(kExprLiteralInt);
|
Expr* e = new Expr(kExprLiteralInt);
|
||||||
e->ival = val;
|
e->ival = val;
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace hsql {
|
||||||
|
|
||||||
// Ternary operators
|
// Ternary operators
|
||||||
BETWEEN,
|
BETWEEN,
|
||||||
|
CASE,
|
||||||
|
|
||||||
// Binary operators.
|
// Binary operators.
|
||||||
SIMPLE_OP,
|
SIMPLE_OP,
|
||||||
|
@ -111,6 +112,8 @@ namespace hsql {
|
||||||
|
|
||||||
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
||||||
|
|
||||||
|
static Expr* makeCase(Expr* expr, Expr* then, Expr* other);
|
||||||
|
|
||||||
static Expr* makeLiteral(int64_t val);
|
static Expr* makeLiteral(int64_t val);
|
||||||
|
|
||||||
static Expr* makeLiteral(double val);
|
static Expr* makeLiteral(double val);
|
||||||
|
|
|
@ -1,7 +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
|
-- 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
|
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 (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
|
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
|
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
|
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
|
N1.N_REGIONKEY = R_REGIONKEY AND R_NAME = 'AMERICA' AND S_NATIONKEY = N2.N_NATIONKEY
|
||||||
|
|
|
@ -184,7 +184,7 @@ TEST(SelectConditionalSelectTest) {
|
||||||
|
|
||||||
SelectStatement* select2 = cond1->expr2->select;
|
SelectStatement* select2 = cond1->expr2->select;
|
||||||
ASSERT_NOTNULL(select2);
|
ASSERT_NOTNULL(select2);
|
||||||
ASSERT_STREQ(select2->fromTable->getName(), "tt")
|
ASSERT_STREQ(select2->fromTable->getName(), "tt");
|
||||||
|
|
||||||
|
|
||||||
// EXISTS (SELECT ...)
|
// EXISTS (SELECT ...)
|
||||||
|
@ -193,7 +193,33 @@ TEST(SelectConditionalSelectTest) {
|
||||||
ASSERT_NOTNULL(cond2->select);
|
ASSERT_NOTNULL(cond2->select);
|
||||||
|
|
||||||
SelectStatement* ex_select = cond2->select;
|
SelectStatement* ex_select = cond2->select;
|
||||||
ASSERT_STREQ(ex_select->fromTable->getName(), "test")
|
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;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue