implement EXISTS conditional

This commit is contained in:
Pedro 2017-03-07 14:37:05 +01:00
parent cf1c84d46d
commit 5605dbab7e
4 changed files with 42 additions and 10 deletions

View File

@ -195,7 +195,8 @@ 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 operand scalar_expr unary_expr binary_expr logic_expr function_expr between_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 <limit> opt_limit opt_top
@ -604,6 +605,7 @@ expr:
operand
| between_expr
| logic_expr
| exists_expr
;
operand:
@ -643,6 +645,10 @@ logic_expr:
| expr OR expr { $$ = Expr::makeOpBinary($1, Expr::OR, $3); }
;
exists_expr:
EXISTS '(' select_no_paren ')' { $$ = Expr::makeExists($3); }
;
comp_expr:
operand '=' operand { $$ = Expr::makeOpBinary($1, '=', $3); }
| operand NOTEQUALS operand { $$ = Expr::makeOpBinary($1, Expr::NOT_EQUALS, $3); }

View File

@ -50,6 +50,7 @@ namespace hsql {
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);
@ -108,6 +109,13 @@ namespace hsql {
return e;
}
Expr* Expr::makeExists(SelectStatement* select) {
Expr* e = new Expr(kExprOperator);
e->opType = EXISTS;
e->select = select;
return e;
}
bool Expr::isType(ExprType e_type) {
return e_type == type;
}

View File

@ -34,6 +34,8 @@ namespace hsql {
// + - * / < > = %
// Non-trivial are: <> <= >= LIKE ISNULL NOT
enum OperatorType {
NONE,
// Ternary operators
BETWEEN,
@ -50,7 +52,8 @@ namespace hsql {
// Unary operators.
NOT,
UMINUS,
ISNULL
ISNULL,
EXISTS
};
@ -123,6 +126,8 @@ namespace hsql {
static Expr* makePlaceholder(int id);
static Expr* makeSelect(SelectStatement* select);
static Expr* makeExists(SelectStatement* select);
};
// Zero initializes an Expr object and assigns it to a space in the heap

View File

@ -160,7 +160,7 @@ TEST(SelectBetweenTest) {
TEST(SelectConditionalSelectTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM t WHERE a = (SELECT MIN(v) FROM tt);",
"SELECT * FROM t WHERE a = (SELECT MIN(v) FROM tt) AND EXISTS (SELECT * FROM test WHERE x < a);",
kStmtSelect,
SelectStatement,
result,
@ -169,18 +169,31 @@ TEST(SelectConditionalSelectTest) {
Expr* where = stmt->whereClause;
ASSERT_NOTNULL(where);
ASSERT(where->isType(kExprOperator));
ASSERT(where->isSimpleOp('='));
ASSERT_EQ(where->opType, Expr::AND);
ASSERT_NOTNULL(where->expr);
ASSERT_STREQ(where->expr->getName(), "a");
ASSERT(where->expr->isType(kExprColumnRef));
// 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(where->expr2);
ASSERT(where->expr2->isType(kExprSelect));
ASSERT_NOTNULL(cond1->expr2);
ASSERT(cond1->expr2->isType(kExprSelect));
SelectStatement* select2 = where->expr2->select;
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;
}