You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by zu...@apache.org on 2016/04/19 18:44:25 UTC

[12/24] incubator-quickstep git commit: Adds support for IN predicate (#167)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/parser/preprocessed/SqlParser_gen.hpp
----------------------------------------------------------------------
diff --git a/parser/preprocessed/SqlParser_gen.hpp b/parser/preprocessed/SqlParser_gen.hpp
index 9447a22..807a39b 100644
--- a/parser/preprocessed/SqlParser_gen.hpp
+++ b/parser/preprocessed/SqlParser_gen.hpp
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.2.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -108,64 +108,65 @@ extern int quickstep_yydebug;
     TOKEN_GROUP = 318,
     TOKEN_HASH = 319,
     TOKEN_HAVING = 320,
-    TOKEN_INDEX = 321,
-    TOKEN_INNER = 322,
-    TOKEN_INSERT = 323,
-    TOKEN_INTEGER = 324,
-    TOKEN_INTERVAL = 325,
-    TOKEN_INTO = 326,
-    TOKEN_JOIN = 327,
-    TOKEN_KEY = 328,
-    TOKEN_LAST = 329,
-    TOKEN_LEFT = 330,
-    TOKEN_LIMIT = 331,
-    TOKEN_LONG = 332,
-    TOKEN_NULL = 333,
-    TOKEN_NULLS = 334,
-    TOKEN_OFF = 335,
-    TOKEN_ON = 336,
-    TOKEN_ORDER = 337,
-    TOKEN_OUTER = 338,
-    TOKEN_PARTITION = 339,
-    TOKEN_PARTITIONS = 340,
-    TOKEN_PERCENT = 341,
-    TOKEN_PRIMARY = 342,
-    TOKEN_QUIT = 343,
-    TOKEN_RANGE = 344,
-    TOKEN_REAL = 345,
-    TOKEN_REFERENCES = 346,
-    TOKEN_RIGHT = 347,
-    TOKEN_ROW_DELIMITER = 348,
-    TOKEN_SELECT = 349,
-    TOKEN_SET = 350,
-    TOKEN_SMA = 351,
-    TOKEN_SMALLINT = 352,
-    TOKEN_TABLE = 353,
-    TOKEN_THEN = 354,
-    TOKEN_TIME = 355,
-    TOKEN_TIMESTAMP = 356,
-    TOKEN_TRUE = 357,
-    TOKEN_TUPLESAMPLE = 358,
-    TOKEN_UNIQUE = 359,
-    TOKEN_UPDATE = 360,
-    TOKEN_USING = 361,
-    TOKEN_VALUES = 362,
-    TOKEN_VARCHAR = 363,
-    TOKEN_WHEN = 364,
-    TOKEN_WHERE = 365,
-    TOKEN_WITH = 366,
-    TOKEN_YEARMONTH = 367,
-    TOKEN_EOF = 368,
-    TOKEN_LEX_ERROR = 369
+    TOKEN_IN = 321,
+    TOKEN_INDEX = 322,
+    TOKEN_INNER = 323,
+    TOKEN_INSERT = 324,
+    TOKEN_INTEGER = 325,
+    TOKEN_INTERVAL = 326,
+    TOKEN_INTO = 327,
+    TOKEN_JOIN = 328,
+    TOKEN_KEY = 329,
+    TOKEN_LAST = 330,
+    TOKEN_LEFT = 331,
+    TOKEN_LIMIT = 332,
+    TOKEN_LONG = 333,
+    TOKEN_NULL = 334,
+    TOKEN_NULLS = 335,
+    TOKEN_OFF = 336,
+    TOKEN_ON = 337,
+    TOKEN_ORDER = 338,
+    TOKEN_OUTER = 339,
+    TOKEN_PARTITION = 340,
+    TOKEN_PARTITIONS = 341,
+    TOKEN_PERCENT = 342,
+    TOKEN_PRIMARY = 343,
+    TOKEN_QUIT = 344,
+    TOKEN_RANGE = 345,
+    TOKEN_REAL = 346,
+    TOKEN_REFERENCES = 347,
+    TOKEN_RIGHT = 348,
+    TOKEN_ROW_DELIMITER = 349,
+    TOKEN_SELECT = 350,
+    TOKEN_SET = 351,
+    TOKEN_SMA = 352,
+    TOKEN_SMALLINT = 353,
+    TOKEN_TABLE = 354,
+    TOKEN_THEN = 355,
+    TOKEN_TIME = 356,
+    TOKEN_TIMESTAMP = 357,
+    TOKEN_TRUE = 358,
+    TOKEN_TUPLESAMPLE = 359,
+    TOKEN_UNIQUE = 360,
+    TOKEN_UPDATE = 361,
+    TOKEN_USING = 362,
+    TOKEN_VALUES = 363,
+    TOKEN_VARCHAR = 364,
+    TOKEN_WHEN = 365,
+    TOKEN_WHERE = 366,
+    TOKEN_WITH = 367,
+    TOKEN_YEARMONTH = 368,
+    TOKEN_EOF = 369,
+    TOKEN_LEX_ERROR = 370
   };
 #endif
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE YYSTYPE;
+
 union YYSTYPE
 {
-#line 116 "../SqlParser.ypp" /* yacc.c:1909  */
+#line 117 "../SqlParser.ypp" /* yacc.c:1915  */
 
   quickstep::ParseString *string_value_;
 
@@ -255,8 +256,10 @@ union YYSTYPE
   quickstep::PtrVector<quickstep::ParseSubqueryTableReference> *with_list_;
   quickstep::ParseSubqueryTableReference *with_list_element_;
 
-#line 259 "SqlParser_gen.hpp" /* yacc.c:1909  */
+#line 260 "SqlParser_gen.hpp" /* yacc.c:1915  */
 };
+
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/parser/tests/Select.test
----------------------------------------------------------------------
diff --git a/parser/tests/Select.test b/parser/tests/Select.test
index 18c3f0d..8a10a12 100644
--- a/parser/tests/Select.test
+++ b/parser/tests/Select.test
@@ -1555,3 +1555,133 @@ SelectStatement
   |       +-right_operand=AttributeReference[attribute_name=col4]
   +-from_clause=
     +-TableReference[table=test]
+==
+
+# IN predicate
+SELECT *
+FROM test 
+WHERE col1 IN (1, 3, 5);
+--
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectStar
+  +-where_clause=InValueList
+  | +-test_expression=AttributeReference[attribute_name=col1]
+  | +-value_list=
+  |   +-Literal
+  |   | +-NumericLiteral[numeric_string=1,float_like=false]
+  |   +-Literal
+  |   | +-NumericLiteral[numeric_string=3,float_like=false]
+  |   +-Literal
+  |     +-NumericLiteral[numeric_string=5,float_like=false]
+  +-from_clause=
+    +-TableReference[table=test]
+==
+
+SELECT *
+FROM test
+WHERE col1 IN (FUN(1),
+               col2+col3,
+               CASE WHEN col4 > 0 THEN col5 ELSE col6 END);
+--
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectStar
+  +-where_clause=InValueList
+  | +-test_expression=AttributeReference[attribute_name=col1]
+  | +-value_list=
+  |   +-FunctionCall[name=FUN]
+  |   | +-Literal
+  |   |   +-NumericLiteral[numeric_string=1,float_like=false]
+  |   +-Add
+  |   | +-left_operand=AttributeReference[attribute_name=col2]
+  |   | +-right_operand=AttributeReference[attribute_name=col3]
+  |   +-SearchedCaseExpression
+  |     +-else_result_expression=AttributeReference[attribute_name=col6]
+  |     +-when_clauses=
+  |       +-SearchedWhenClause
+  |         +-condition_predicate=Greater
+  |         | +-left_operand=AttributeReference[attribute_name=col4]
+  |         | +-right_operand=Literal
+  |         |   +-NumericLiteral[numeric_string=0,float_like=false]
+  |         +-result_expression=AttributeReference[attribute_name=col5]
+  +-from_clause=
+    +-TableReference[table=test]
+==
+
+SELECT *
+FROM test
+WHERE col1 NOT IN (col1, col2 + col3);
+--
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectStar
+  +-where_clause=Not
+  | +-InValueList
+  |   +-test_expression=AttributeReference[attribute_name=col1]
+  |   +-value_list=
+  |     +-AttributeReference[attribute_name=col1]
+  |     +-Add
+  |       +-left_operand=AttributeReference[attribute_name=col2]
+  |       +-right_operand=AttributeReference[attribute_name=col3]
+  +-from_clause=
+    +-TableReference[table=test]
+==
+
+SELECT *
+FROM test
+WHERE col1 IN (
+  SELECT SUM(col2+col3)
+  FROM bar
+  GROUP BY col4
+);
+--
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectStar
+  +-where_clause=InTableQuery
+  | +-test_expression=AttributeReference[attribute_name=col1]
+  | +-table_query=SubqueryExpression
+  |   +-Select
+  |     +-select_clause=SelectList
+  |     | +-SelectListItem
+  |     |   +-FunctionCall[name=SUM]
+  |     |     +-Add
+  |     |       +-left_operand=AttributeReference[attribute_name=col2]
+  |     |       +-right_operand=AttributeReference[attribute_name=col3]
+  |     +-group_by=GroupBy
+  |     | +-AttributeReference[attribute_name=col4]
+  |     +-from_clause=
+  |       +-TableReference[table=bar]
+  +-from_clause=
+    +-TableReference[table=test]
+==
+
+SELECT *
+FROM test
+WHERE col1 NOT IN (
+  SELECT col2
+  FROM bar
+  WHERE col3 IN (col4, col5)
+);
+--
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectStar
+  +-where_clause=Not
+  | +-InTableQuery
+  |   +-test_expression=AttributeReference[attribute_name=col1]
+  |   +-table_query=SubqueryExpression
+  |     +-Select
+  |       +-select_clause=SelectList
+  |       | +-SelectListItem
+  |       |   +-AttributeReference[attribute_name=col2]
+  |       +-where_clause=InValueList
+  |       | +-test_expression=AttributeReference[attribute_name=col3]
+  |       | +-value_list=
+  |       |   +-AttributeReference[attribute_name=col4]
+  |       |   +-AttributeReference[attribute_name=col5]
+  |       +-from_clause=
+  |         +-TableReference[table=bar]
+  +-from_clause=
+    +-TableReference[table=test]

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/parser/tests/TPCH.test
----------------------------------------------------------------------
diff --git a/parser/tests/TPCH.test b/parser/tests/TPCH.test
index 45071e4..dfcd6aa 100644
--- a/parser/tests/TPCH.test
+++ b/parser/tests/TPCH.test
@@ -974,7 +974,7 @@ FROM
   lineitem
 WHERE
   o_orderkey = l_orderkey
-  AND l_shipmode in ('REG AIR', 'RAIL')
+  AND l_shipmode IN ('REG AIR', 'RAIL')
   AND l_commitdate < l_receiptdate
   AND l_shipdate < l_commitdate
   AND l_receiptdate >= DATE '1997-01-01'
@@ -984,9 +984,87 @@ GROUP BY
 ORDER BY
   l_shipmode
 --
-ERROR: syntax error (20 : 18)
-  AND l_shipmode in ('REG AIR', 'RAIL')
-                 ^
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectList
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=l_shipmode]
+  | +-SelectListItem[alias=high_line_count]
+  | | +-FunctionCall[name=SUM]
+  | |   +-SearchedCaseExpression
+  | |     +-else_result_expression=Literal
+  | |     | +-NumericLiteral[numeric_string=0,float_like=false]
+  | |     +-when_clauses=
+  | |       +-SearchedWhenClause
+  | |         +-condition_predicate=Or
+  | |         | +-Equal
+  | |         | | +-left_operand=AttributeReference[
+  | |         | | | attribute_name=o_orderpriority]
+  | |         | | +-right_operand=Literal
+  | |         | |   +-StringLiteral[value=1-URGENT]
+  | |         | +-Equal
+  | |         |   +-left_operand=AttributeReference[
+  | |         |   | attribute_name=o_orderpriority]
+  | |         |   +-right_operand=Literal
+  | |         |     +-StringLiteral[value=2-HIGH]
+  | |         +-result_expression=Literal
+  | |           +-NumericLiteral[numeric_string=1,float_like=false]
+  | +-SelectListItem[alias=low_line_count]
+  |   +-FunctionCall[name=SUM]
+  |     +-SearchedCaseExpression
+  |       +-else_result_expression=Literal
+  |       | +-NumericLiteral[numeric_string=0,float_like=false]
+  |       +-when_clauses=
+  |         +-SearchedWhenClause
+  |           +-condition_predicate=And
+  |           | +-NotEqual
+  |           | | +-left_operand=AttributeReference[
+  |           | | | attribute_name=o_orderpriority]
+  |           | | +-right_operand=Literal
+  |           | |   +-StringLiteral[value=1-URGENT]
+  |           | +-NotEqual
+  |           |   +-left_operand=AttributeReference[
+  |           |   | attribute_name=o_orderpriority]
+  |           |   +-right_operand=Literal
+  |           |     +-StringLiteral[value=2-HIGH]
+  |           +-result_expression=Literal
+  |             +-NumericLiteral[numeric_string=1,float_like=false]
+  +-where_clause=And
+  | +-Equal
+  | | +-left_operand=AttributeReference[attribute_name=o_orderkey]
+  | | +-right_operand=AttributeReference[attribute_name=l_orderkey]
+  | +-InValueList
+  | | +-test_expression=AttributeReference[attribute_name=l_shipmode]
+  | | +-value_list=
+  | |   +-Literal
+  | |   | +-StringLiteral[value=REG AIR]
+  | |   +-Literal
+  | |     +-StringLiteral[value=RAIL]
+  | +-Less
+  | | +-left_operand=AttributeReference[attribute_name=l_commitdate]
+  | | +-right_operand=AttributeReference[attribute_name=l_receiptdate]
+  | +-Less
+  | | +-left_operand=AttributeReference[attribute_name=l_shipdate]
+  | | +-right_operand=AttributeReference[attribute_name=l_commitdate]
+  | +-GreaterOrEqual
+  | | +-left_operand=AttributeReference[attribute_name=l_receiptdate]
+  | | +-right_operand=Literal
+  | |   +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  | +-Less
+  |   +-left_operand=AttributeReference[attribute_name=l_receiptdate]
+  |   +-right_operand=Add
+  |     +-left_operand=Literal
+  |     | +-StringLiteral[value=1997-01-01,explicit_type=Datetime]
+  |     +-right_operand=Literal
+  |       +-StringLiteral[value=1 year,explicit_type=YearMonthInterval]
+  +-group_by=GroupBy
+  | +-AttributeReference[attribute_name=l_shipmode]
+  +-order_by=OrderBy
+  | +-OrderByItem[is_asc=true,nulls_first=false]
+  |   +-AttributeReference[attribute_name=l_shipmode]
+  +-from_clause=
+    +-TableReference[table=orders]
+    +-TableReference[table=lineitem]
 ==
 
 # Query 13
@@ -1152,9 +1230,79 @@ ORDER BY
   p_type,
   p_size
 --
-ERROR: syntax error (13 : 14)
-  AND p_size IN (32, 42, 9, 18, 50, 30, 12,...
-             ^
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectList
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=p_brand]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=p_type]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=p_size]
+  | +-SelectListItem[alias=supplier_cnt]
+  |   +-FunctionCall[name=COUNT,is_distinct=true]
+  |     +-AttributeReference[attribute_name=ps_suppkey]
+  +-where_clause=And
+  | +-Equal
+  | | +-left_operand=AttributeReference[attribute_name=p_partkey]
+  | | +-right_operand=AttributeReference[attribute_name=ps_partkey]
+  | +-NotEqual
+  | | +-left_operand=AttributeReference[attribute_name=p_brand]
+  | | +-right_operand=Literal
+  | |   +-StringLiteral[value=Brand#22]
+  | +-NotLike
+  | | +-left_operand=AttributeReference[attribute_name=p_type]
+  | | +-right_operand=Literal
+  | |   +-StringLiteral[value=ECONOMY BURNISHED%]
+  | +-InValueList
+  | | +-test_expression=AttributeReference[attribute_name=p_size]
+  | | +-value_list=
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=32,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=42,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=9,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=18,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=50,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=30,float_like=false]
+  | |   +-Literal
+  | |   | +-NumericLiteral[numeric_string=12,float_like=false]
+  | |   +-Literal
+  | |     +-NumericLiteral[numeric_string=21,float_like=false]
+  | +-Not
+  |   +-InTableQuery
+  |     +-test_expression=AttributeReference[attribute_name=ps_suppkey]
+  |     +-table_query=SubqueryExpression
+  |       +-Select
+  |         +-select_clause=SelectList
+  |         | +-SelectListItem
+  |         |   +-AttributeReference[attribute_name=s_suppkey]
+  |         +-where_clause=Like
+  |         | +-left_operand=AttributeReference[attribute_name=s_comment]
+  |         | +-right_operand=Literal
+  |         |   +-StringLiteral[value=%Customer%Complaints%]
+  |         +-from_clause=
+  |           +-TableReference[table=supplier]
+  +-group_by=GroupBy
+  | +-AttributeReference[attribute_name=p_brand]
+  | +-AttributeReference[attribute_name=p_type]
+  | +-AttributeReference[attribute_name=p_size]
+  +-order_by=OrderBy
+  | +-OrderByItem[is_asc=false,nulls_first=true]
+  | | +-AttributeReference[attribute_name=supplier_cnt]
+  | +-OrderByItem[is_asc=true,nulls_first=false]
+  | | +-AttributeReference[attribute_name=p_brand]
+  | +-OrderByItem[is_asc=true,nulls_first=false]
+  | | +-AttributeReference[attribute_name=p_type]
+  | +-OrderByItem[is_asc=true,nulls_first=false]
+  |   +-AttributeReference[attribute_name=p_size]
+  +-from_clause=
+    +-TableReference[table=partsupp]
+    +-TableReference[table=part]
 ==
 
 # Query 17
@@ -1194,7 +1342,7 @@ FROM
   orders,
   lineitem
 WHERE
-  o_orderkey in (
+  o_orderkey IN (
     SELECT
       l_orderkey
     FROM
@@ -1216,9 +1364,63 @@ ORDER BY
   o_orderdate
 LIMIT 100
 --
-ERROR: syntax error (13 : 14)
-  o_orderkey in (
-             ^
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectList
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=c_name]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=c_custkey]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=o_orderkey]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=o_orderdate]
+  | +-SelectListItem
+  | | +-AttributeReference[attribute_name=o_totalprice]
+  | +-SelectListItem
+  |   +-FunctionCall[name=sum]
+  |     +-AttributeReference[attribute_name=l_quantity]
+  +-where_clause=And
+  | +-InTableQuery
+  | | +-test_expression=AttributeReference[attribute_name=o_orderkey]
+  | | +-table_query=SubqueryExpression
+  | |   +-Select
+  | |     +-select_clause=SelectList
+  | |     | +-SelectListItem
+  | |     |   +-AttributeReference[attribute_name=l_orderkey]
+  | |     +-group_by=GroupBy
+  | |     | +-AttributeReference[attribute_name=l_orderkey]
+  | |     +-having=HAVING
+  | |     | +-Greater
+  | |     |   +-left_operand=FunctionCall[name=SUM]
+  | |     |   | +-AttributeReference[attribute_name=l_quantity]
+  | |     |   +-right_operand=Literal
+  | |     |     +-NumericLiteral[numeric_string=314,float_like=false]
+  | |     +-from_clause=
+  | |       +-TableReference[table=lineitem]
+  | +-Equal
+  | | +-left_operand=AttributeReference[attribute_name=c_custkey]
+  | | +-right_operand=AttributeReference[attribute_name=o_custkey]
+  | +-Equal
+  |   +-left_operand=AttributeReference[attribute_name=o_orderkey]
+  |   +-right_operand=AttributeReference[attribute_name=l_orderkey]
+  +-group_by=GroupBy
+  | +-AttributeReference[attribute_name=c_name]
+  | +-AttributeReference[attribute_name=c_custkey]
+  | +-AttributeReference[attribute_name=o_orderkey]
+  | +-AttributeReference[attribute_name=o_orderdate]
+  | +-AttributeReference[attribute_name=o_totalprice]
+  +-order_by=OrderBy
+  | +-OrderByItem[is_asc=false,nulls_first=true]
+  | | +-AttributeReference[attribute_name=o_totalprice]
+  | +-OrderByItem[is_asc=true,nulls_first=false]
+  |   +-AttributeReference[attribute_name=o_orderdate]
+  +-limit=LIMIT
+  | +-NumericLiteral[numeric_string=100,float_like=false]
+  +-from_clause=
+    +-TableReference[table=customer]
+    +-TableReference[table=orders]
+    +-TableReference[table=lineitem]
 ==
 
 # Query 19
@@ -1258,9 +1460,162 @@ WHERE
     AND l_shipinstruct = 'DELIVER IN PERSON'
   )
 --
-ERROR: syntax error (10 : 21)
-    AND p_container IN ('SM CASE', 'SM BOX', 'SM PAC...
-                    ^
+SelectStatement
++-select_query=Select
+  +-select_clause=SelectList
+  | +-SelectListItem[alias=revenue]
+  |   +-FunctionCall[name=SUM]
+  |     +-Multiply
+  |       +-left_operand=AttributeReference[attribute_name=l_extendedprice]
+  |       +-right_operand=Subtract
+  |         +-left_operand=Literal
+  |         | +-NumericLiteral[numeric_string=1,float_like=false]
+  |         +-right_operand=AttributeReference[attribute_name=l_discount]
+  +-where_clause=Or
+  | +-And
+  | | +-Equal
+  | | | +-left_operand=AttributeReference[attribute_name=p_partkey]
+  | | | +-right_operand=AttributeReference[attribute_name=l_partkey]
+  | | +-Equal
+  | | | +-left_operand=AttributeReference[attribute_name=p_brand]
+  | | | +-right_operand=Literal
+  | | |   +-StringLiteral[value=Brand#45]
+  | | +-InValueList
+  | | | +-test_expression=AttributeReference[attribute_name=p_container]
+  | | | +-value_list=
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=SM CASE]
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=SM BOX]
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=SM PACK]
+  | | |   +-Literal
+  | | |     +-StringLiteral[value=SM PKG]
+  | | +-GreaterOrEqual
+  | | | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  | | | +-right_operand=Literal
+  | | |   +-NumericLiteral[numeric_string=2,float_like=false]
+  | | +-LessOrEqual
+  | | | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  | | | +-right_operand=Add
+  | | |   +-left_operand=Literal
+  | | |   | +-NumericLiteral[numeric_string=2,float_like=false]
+  | | |   +-right_operand=Literal
+  | | |     +-NumericLiteral[numeric_string=10,float_like=false]
+  | | +-Between
+  | | | +-check_operand=AttributeReference[attribute_name=p_size]
+  | | | +-lower_bound_operand=Literal
+  | | | | +-NumericLiteral[numeric_string=1,float_like=false]
+  | | | +-upper_bound_operand=Literal
+  | | |   +-NumericLiteral[numeric_string=5,float_like=false]
+  | | +-InValueList
+  | | | +-test_expression=AttributeReference[attribute_name=l_shipmode]
+  | | | +-value_list=
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=AIR]
+  | | |   +-Literal
+  | | |     +-StringLiteral[value=AIR REG]
+  | | +-Equal
+  | |   +-left_operand=AttributeReference[attribute_name=l_shipinstruct]
+  | |   +-right_operand=Literal
+  | |     +-StringLiteral[value=DELIVER IN PERSON]
+  | +-And
+  | | +-Equal
+  | | | +-left_operand=AttributeReference[attribute_name=p_partkey]
+  | | | +-right_operand=AttributeReference[attribute_name=l_partkey]
+  | | +-Equal
+  | | | +-left_operand=AttributeReference[attribute_name=p_brand]
+  | | | +-right_operand=Literal
+  | | |   +-StringLiteral[value=Brand#12]
+  | | +-InValueList
+  | | | +-test_expression=AttributeReference[attribute_name=p_container]
+  | | | +-value_list=
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=MED BAG]
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=MED BOX]
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=MED PKG]
+  | | |   +-Literal
+  | | |     +-StringLiteral[value=MED PACK]
+  | | +-GreaterOrEqual
+  | | | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  | | | +-right_operand=Literal
+  | | |   +-NumericLiteral[numeric_string=13,float_like=false]
+  | | +-LessOrEqual
+  | | | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  | | | +-right_operand=Add
+  | | |   +-left_operand=Literal
+  | | |   | +-NumericLiteral[numeric_string=13,float_like=false]
+  | | |   +-right_operand=Literal
+  | | |     +-NumericLiteral[numeric_string=10,float_like=false]
+  | | +-Between
+  | | | +-check_operand=AttributeReference[attribute_name=p_size]
+  | | | +-lower_bound_operand=Literal
+  | | | | +-NumericLiteral[numeric_string=1,float_like=false]
+  | | | +-upper_bound_operand=Literal
+  | | |   +-NumericLiteral[numeric_string=10,float_like=false]
+  | | +-InValueList
+  | | | +-test_expression=AttributeReference[attribute_name=l_shipmode]
+  | | | +-value_list=
+  | | |   +-Literal
+  | | |   | +-StringLiteral[value=AIR]
+  | | |   +-Literal
+  | | |     +-StringLiteral[value=AIR REG]
+  | | +-Equal
+  | |   +-left_operand=AttributeReference[attribute_name=l_shipinstruct]
+  | |   +-right_operand=Literal
+  | |     +-StringLiteral[value=DELIVER IN PERSON]
+  | +-And
+  |   +-Equal
+  |   | +-left_operand=AttributeReference[attribute_name=p_partkey]
+  |   | +-right_operand=AttributeReference[attribute_name=l_partkey]
+  |   +-Equal
+  |   | +-left_operand=AttributeReference[attribute_name=p_brand]
+  |   | +-right_operand=Literal
+  |   |   +-StringLiteral[value=Brand#53]
+  |   +-InValueList
+  |   | +-test_expression=AttributeReference[attribute_name=p_container]
+  |   | +-value_list=
+  |   |   +-Literal
+  |   |   | +-StringLiteral[value=LG CASE]
+  |   |   +-Literal
+  |   |   | +-StringLiteral[value=LG BOX]
+  |   |   +-Literal
+  |   |   | +-StringLiteral[value=LG PACK]
+  |   |   +-Literal
+  |   |     +-StringLiteral[value=LG PKG]
+  |   +-GreaterOrEqual
+  |   | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  |   | +-right_operand=Literal
+  |   |   +-NumericLiteral[numeric_string=24,float_like=false]
+  |   +-LessOrEqual
+  |   | +-left_operand=AttributeReference[attribute_name=l_quantity]
+  |   | +-right_operand=Add
+  |   |   +-left_operand=Literal
+  |   |   | +-NumericLiteral[numeric_string=24,float_like=false]
+  |   |   +-right_operand=Literal
+  |   |     +-NumericLiteral[numeric_string=10,float_like=false]
+  |   +-Between
+  |   | +-check_operand=AttributeReference[attribute_name=p_size]
+  |   | +-lower_bound_operand=Literal
+  |   | | +-NumericLiteral[numeric_string=1,float_like=false]
+  |   | +-upper_bound_operand=Literal
+  |   |   +-NumericLiteral[numeric_string=15,float_like=false]
+  |   +-InValueList
+  |   | +-test_expression=AttributeReference[attribute_name=l_shipmode]
+  |   | +-value_list=
+  |   |   +-Literal
+  |   |   | +-StringLiteral[value=AIR]
+  |   |   +-Literal
+  |   |     +-StringLiteral[value=AIR REG]
+  |   +-Equal
+  |     +-left_operand=AttributeReference[attribute_name=l_shipinstruct]
+  |     +-right_operand=Literal
+  |       +-StringLiteral[value=DELIVER IN PERSON]
+  +-from_clause=
+    +-TableReference[table=lineitem]
+    +-TableReference[table=part]
 ==
 
 # Query 20
@@ -1271,7 +1626,7 @@ FROM
   supplier,
   nation
 WHERE
-  s_suppkey in (
+  s_suppkey IN (
     SELECT
       ps_suppkey
     FROM
@@ -1302,9 +1657,9 @@ WHERE
 ORDER BY
   s_name
 --
-ERROR: syntax error (8 : 13)
-  s_suppkey in (
-            ^
+ERROR: syntax error (23 : 9)
+        SELECT
+        ^
 ==
 
 # Query 21
@@ -1453,7 +1808,7 @@ FROM
     FROM
       customer
     WHERE
-      SUBSTR(c_phone, 1, 2) in
+      SUBSTR(c_phone, 1, 2) IN
         ('27', '44', '34', '25', '30', '33', '23')
       AND c_acctbal > (
         SELECT
@@ -1462,10 +1817,10 @@ FROM
           customer
         WHERE
           c_acctbal > 0.00
-          AND SUBSTR(c_phone, 1, 2) in
+          AND SUBSTR(c_phone, 1, 2) IN
             ('27', '44', '34', '25', '30', '33', '23')
       )
-      AND NOT exists (
+      AND NOT EXISTS (
         SELECT *
         FROM
           orders
@@ -1478,6 +1833,6 @@ GROUP BY
 ORDER BY
   cntrycode
 --
-ERROR: syntax error (13 : 29)
-      SUBSTR(c_phone, 1, 2) in
-                            ^
+ERROR: syntax error (16 : 9)
+        SELECT
+        ^

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/CMakeLists.txt b/query_optimizer/expressions/CMakeLists.txt
index ca064dc..6c40741 100644
--- a/query_optimizer/expressions/CMakeLists.txt
+++ b/query_optimizer/expressions/CMakeLists.txt
@@ -28,6 +28,8 @@ add_library(quickstep_queryoptimizer_expressions_Expression ../../empty_src.cpp
 add_library(quickstep_queryoptimizer_expressions_ExpressionType ../../empty_src.cpp ExpressionType.hpp)
 add_library(quickstep_queryoptimizer_expressions_ExprId ../../empty_src.cpp ExprId.hpp)
 add_library(quickstep_queryoptimizer_expressions_ExpressionUtil ExpressionUtil.cpp ExpressionUtil.hpp)
+add_library(quickstep_queryoptimizer_expressions_InTableQuery InTableQuery.cpp InTableQuery.hpp)
+add_library(quickstep_queryoptimizer_expressions_InValueList InValueList.cpp InValueList.hpp)
 add_library(quickstep_queryoptimizer_expressions_LogicalAnd LogicalAnd.cpp LogicalAnd.hpp)
 add_library(quickstep_queryoptimizer_expressions_LogicalNot LogicalNot.cpp LogicalNot.hpp)
 add_library(quickstep_queryoptimizer_expressions_LogicalOr LogicalOr.cpp LogicalOr.hpp)
@@ -138,6 +140,31 @@ target_link_libraries(quickstep_queryoptimizer_expressions_ExpressionUtil
                       quickstep_queryoptimizer_expressions_ExprId
                       quickstep_queryoptimizer_expressions_NamedExpression
                       quickstep_queryoptimizer_expressions_PatternMatcher)
+target_link_libraries(quickstep_queryoptimizer_expressions_InTableQuery
+                      quickstep_queryoptimizer_OptimizerTree
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_queryoptimizer_expressions_ExprId
+                      quickstep_queryoptimizer_expressions_Expression
+                      quickstep_queryoptimizer_expressions_ExpressionType
+                      quickstep_queryoptimizer_expressions_Predicate
+                      quickstep_queryoptimizer_expressions_Scalar
+                      quickstep_queryoptimizer_expressions_SubqueryExpression
+                      quickstep_utility_Macros)
+target_link_libraries(quickstep_queryoptimizer_expressions_InValueList
+                      quickstep_queryoptimizer_OptimizerTree
+                      quickstep_expressions_predicate_DisjunctionPredicate
+                      quickstep_expressions_predicate_Predicate
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_queryoptimizer_expressions_ComparisonExpression
+                      quickstep_queryoptimizer_expressions_ExprId
+                      quickstep_queryoptimizer_expressions_Expression
+                      quickstep_queryoptimizer_expressions_ExpressionType
+                      quickstep_queryoptimizer_expressions_Predicate
+                      quickstep_queryoptimizer_expressions_Scalar
+                      quickstep_types_operations_comparisons_ComparisonFactory
+                      quickstep_types_operations_comparisons_ComparisonID
+                      quickstep_utility_Cast
+                      quickstep_utility_Macros)
 target_link_libraries(quickstep_queryoptimizer_expressions_LogicalAnd
                       glog
                       quickstep_expressions_predicate_ConjunctionPredicate
@@ -289,6 +316,8 @@ target_link_libraries(quickstep_queryoptimizer_expressions
                       quickstep_queryoptimizer_expressions_ExpressionType
                       quickstep_queryoptimizer_expressions_ExprId
                       quickstep_queryoptimizer_expressions_ExpressionUtil
+                      quickstep_queryoptimizer_expressions_InTableQuery
+                      quickstep_queryoptimizer_expressions_InValueList
                       quickstep_queryoptimizer_expressions_LogicalAnd
                       quickstep_queryoptimizer_expressions_LogicalNot
                       quickstep_queryoptimizer_expressions_LogicalOr

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/ExpressionType.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/ExpressionType.hpp b/query_optimizer/expressions/ExpressionType.hpp
index afd6f81..23770e0 100644
--- a/query_optimizer/expressions/ExpressionType.hpp
+++ b/query_optimizer/expressions/ExpressionType.hpp
@@ -39,6 +39,8 @@ enum class ExpressionType {
   kCast,
   kComparisonExpression,
   kExists,
+  kInTableQuery,
+  kInValueList,
   kLogicalAnd,
   kLogicalOr,
   kLogicalNot,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/InTableQuery.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/InTableQuery.cpp b/query_optimizer/expressions/InTableQuery.cpp
new file mode 100644
index 0000000..b4abbe0
--- /dev/null
+++ b/query_optimizer/expressions/InTableQuery.cpp
@@ -0,0 +1,53 @@
+/**
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin—Madison.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ **/
+
+#include "query_optimizer/expressions/InTableQuery.hpp"
+
+#include <string>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+namespace optimizer {
+namespace expressions {
+
+::quickstep::Predicate* InTableQuery::concretize(
+    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const {
+  LOG(FATAL) << "InTableQuery predicate should not be concretized";
+}
+
+void InTableQuery::getFieldStringItems(
+    std::vector<std::string> *inline_field_names,
+    std::vector<std::string> *inline_field_values,
+    std::vector<std::string> *non_container_child_field_names,
+    std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+    std::vector<std::string> *container_child_field_names,
+    std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const {
+  non_container_child_field_names->push_back("test_expression");
+  non_container_child_fields->push_back(test_expression_);
+
+  non_container_child_field_names->push_back("table_query");
+  non_container_child_fields->push_back(table_query_);
+}
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/InTableQuery.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/InTableQuery.hpp b/query_optimizer/expressions/InTableQuery.hpp
new file mode 100644
index 0000000..e4abf22
--- /dev/null
+++ b/query_optimizer/expressions/InTableQuery.hpp
@@ -0,0 +1,143 @@
+/**
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin—Madison.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_TABLE_QUERY_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_TABLE_QUERY_HPP_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
+#include "query_optimizer/expressions/Expression.hpp"
+#include "query_optimizer/expressions/ExpressionType.hpp"
+#include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/expressions/Scalar.hpp"
+#include "query_optimizer/expressions/SubqueryExpression.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+class CatalogAttribute;
+class Predicate;
+
+namespace optimizer {
+namespace expressions {
+
+/** \addtogroup OptimizerExpressions
+ *  @{
+ */
+
+class InTableQuery;
+typedef std::shared_ptr<const InTableQuery> InTableQueryPtr;
+
+/**
+ * @brief IN predicate with a subquery.
+ */
+class InTableQuery : public Predicate {
+ public:
+  ExpressionType getExpressionType() const override {
+    return ExpressionType::kInTableQuery;
+  }
+
+  std::string getName() const override {
+    return "InTableQuery";
+  }
+
+  bool isConstant() const override {
+    return false;
+  }
+
+  /**
+   * @return The expression to test with the result of the table subquery.
+   */
+  const ScalarPtr& test_expression() const {
+    return test_expression_;
+  }
+
+  /**
+   * @return The table subquery that returns a single column to search for
+   *         the value of the test expression.
+   */
+  const SubqueryExpressionPtr& table_query() const {
+    return table_query_;
+  }
+
+  ExpressionPtr copyWithNewChildren(
+      const std::vector<ExpressionPtr> &new_children) const override {
+    DCHECK_EQ(2u, new_children.size());
+    return Create(std::static_pointer_cast<const Scalar>(new_children[0]),
+                  std::static_pointer_cast<const SubqueryExpression>(new_children[1]));
+  }
+
+  std::vector<AttributeReferencePtr> getReferencedAttributes() const override {
+    return {};
+  }
+
+  ::quickstep::Predicate* concretize(
+      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override;
+
+  /**
+   * @brief Create an IN predicate with a subquery.
+   *
+   * @param test_expression The expression to test with the result of a table subquery.
+   * @param table_query The table subquery that returns a single column to search for
+   *        the value of the test expression.
+   *
+   * @return An immutable IN predicate node.
+   */
+  static InTableQueryPtr Create(const ScalarPtr &test_expression,
+                                const SubqueryExpressionPtr &table_query) {
+    return InTableQueryPtr(new InTableQuery(test_expression, table_query));
+  }
+
+ protected:
+  void getFieldStringItems(
+      std::vector<std::string> *inline_field_names,
+      std::vector<std::string> *inline_field_values,
+      std::vector<std::string> *non_container_child_field_names,
+      std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+      std::vector<std::string> *container_child_field_names,
+      std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const override;
+
+ private:
+  InTableQuery(const ScalarPtr &test_expression,
+               const SubqueryExpressionPtr &table_query)
+      : test_expression_(test_expression),
+        table_query_(table_query) {
+    addChild(test_expression_);
+    addChild(table_query_);
+  }
+
+  ScalarPtr test_expression_;
+  SubqueryExpressionPtr table_query_;
+
+  DISALLOW_COPY_AND_ASSIGN(InTableQuery);
+};
+
+/** @} */
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_TABLE_QUERY_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/InValueList.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/InValueList.cpp b/query_optimizer/expressions/InValueList.cpp
new file mode 100644
index 0000000..dd77d95
--- /dev/null
+++ b/query_optimizer/expressions/InValueList.cpp
@@ -0,0 +1,72 @@
+/**
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin—Madison.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ **/
+
+#include "query_optimizer/expressions/InValueList.hpp"
+
+#include <string>
+#include <vector>
+
+#include "expressions/predicate/DisjunctionPredicate.hpp"
+#include "expressions/predicate/Predicate.hpp"
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/ComparisonExpression.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
+#include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/expressions/Scalar.hpp"
+#include "types/operations/comparisons/ComparisonID.hpp"
+#include "types/operations/comparisons/ComparisonFactory.hpp"
+#include "utility/Cast.hpp"
+
+namespace quickstep {
+namespace optimizer {
+namespace expressions {
+
+::quickstep::Predicate* InValueList::concretize(
+    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const {
+  std::unique_ptr<quickstep::DisjunctionPredicate>
+      disjunction_predicate(new quickstep::DisjunctionPredicate());
+  for (const ScalarPtr &match_expression : match_expressions_) {
+    const PredicatePtr match_predicate =
+        ComparisonExpression::Create(
+            quickstep::ComparisonFactory::GetComparison(quickstep::ComparisonID::kEqual),
+            test_expression_,
+            match_expression);
+
+    disjunction_predicate->addPredicate(
+        match_predicate->concretize(substitution_map));
+  }
+  return disjunction_predicate.release();
+}
+
+void InValueList::getFieldStringItems(
+    std::vector<std::string> *inline_field_names,
+    std::vector<std::string> *inline_field_values,
+    std::vector<std::string> *non_container_child_field_names,
+    std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+    std::vector<std::string> *container_child_field_names,
+    std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const {
+  non_container_child_field_names->push_back("test_expression");
+  non_container_child_fields->push_back(test_expression_);
+
+  container_child_field_names->push_back("match_expressions");
+  container_child_fields->push_back(
+      CastSharedPtrVector<OptimizerTreeBase>(match_expressions_));
+}
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/InValueList.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/InValueList.hpp b/query_optimizer/expressions/InValueList.hpp
new file mode 100644
index 0000000..9fc2ace
--- /dev/null
+++ b/query_optimizer/expressions/InValueList.hpp
@@ -0,0 +1,157 @@
+/**
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin—Madison.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_VALUE_LIST_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_VALUE_LIST_HPP_
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
+#include "query_optimizer/expressions/Expression.hpp"
+#include "query_optimizer/expressions/ExpressionType.hpp"
+#include "query_optimizer/expressions/Predicate.hpp"
+#include "query_optimizer/expressions/Scalar.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+class CatalogAttribute;
+class Predicate;
+
+namespace optimizer {
+namespace expressions {
+
+/** \addtogroup OptimizerExpressions
+ *  @{
+ */
+
+class InValueList;
+typedef std::shared_ptr<const InValueList> InValueListPtr;
+
+/**
+ * @brief IN predicate with a value list.
+ */
+class InValueList : public Predicate {
+ public:
+  ExpressionType getExpressionType() const override {
+    return ExpressionType::kInValueList;
+  }
+
+  std::string getName() const override {
+    return "InValueList";
+  }
+
+  bool isConstant() const override {
+    return false;
+  }
+
+  /**
+   * @return The expression to test with a value list.
+   */
+  const ScalarPtr& test_expression() const {
+    return test_expression_;
+  }
+
+  /**
+   * @return Expressions to search for the value of the test_expression.
+   */
+  const std::vector<ScalarPtr>& match_expressions() const {
+    return match_expressions_;
+  }
+
+  ExpressionPtr copyWithNewChildren(
+      const std::vector<ExpressionPtr> &new_children) const override {
+    DCHECK_EQ(children().size(), new_children.size());
+    std::vector<ScalarPtr> new_match_expressions;
+    for (std::size_t idx = 1; idx < new_children.size(); ++idx) {
+      new_match_expressions.emplace_back(
+          std::static_pointer_cast<const Scalar>(new_children[idx]));
+    }
+    return Create(std::static_pointer_cast<const Scalar>(new_children[0]),
+                  new_match_expressions);
+  }
+
+  std::vector<AttributeReferencePtr> getReferencedAttributes() const override {
+    std::vector<AttributeReferencePtr> referenced_attrs =
+        test_expression_->getReferencedAttributes();
+    for (const ScalarPtr &match_expression : match_expressions_) {
+      const std::vector<AttributeReferencePtr> referenced_attrs_in_match_expr =
+          match_expression->getReferencedAttributes();
+      referenced_attrs.insert(referenced_attrs.end(),
+                              referenced_attrs_in_match_expr.begin(),
+                              referenced_attrs_in_match_expr.end());
+    }
+    return referenced_attrs;
+  }
+
+  ::quickstep::Predicate* concretize(
+      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override;
+
+  /**
+   * @brief Create an IN predicate with a value list.
+   *
+   * @param test_expression The expression to test with a value list.
+   * @param match_expressions Expressions to search for the value of the test_expression.
+   *
+   * @return An immutable IN predicate node with a value list.
+   */
+  static InValueListPtr Create(const ScalarPtr &test_expression,
+                               const std::vector<ScalarPtr> &match_expressions) {
+    return InValueListPtr(new InValueList(test_expression, match_expressions));
+  }
+
+ protected:
+  void getFieldStringItems(
+      std::vector<std::string> *inline_field_names,
+      std::vector<std::string> *inline_field_values,
+      std::vector<std::string> *non_container_child_field_names,
+      std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+      std::vector<std::string> *container_child_field_names,
+      std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const override;
+
+ private:
+  InValueList(const ScalarPtr &test_expression,
+              const std::vector<ScalarPtr> &match_expressions)
+      : test_expression_(test_expression),
+        match_expressions_(match_expressions) {
+    addChild(test_expression_);
+    for (const ScalarPtr &match_expression : match_expressions_) {
+      addChild(match_expression);
+    }
+  }
+
+  ScalarPtr test_expression_;
+  std::vector<ScalarPtr> match_expressions_;
+
+  DISALLOW_COPY_AND_ASSIGN(InValueList);
+};
+
+/** @} */
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_IN_VALUE_LIST_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/expressions/PatternMatcher.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/PatternMatcher.hpp b/query_optimizer/expressions/PatternMatcher.hpp
index 528b1e6..87bc52a 100644
--- a/query_optimizer/expressions/PatternMatcher.hpp
+++ b/query_optimizer/expressions/PatternMatcher.hpp
@@ -38,6 +38,8 @@ class Cast;
 class ComparisonExpression;
 class Count;
 class Exists;
+class InTableQuery;
+class InValueList;
 class LogicalAnd;
 class LogicalNot;
 class LogicalOr;
@@ -119,6 +121,8 @@ using SomeBinaryExpression = SomeExpressionNode<BinaryExpression, ExpressionType
 using SomeCast = SomeExpressionNode<Cast, ExpressionType::kCast>;
 using SomeComparisonExpression = SomeExpressionNode<ComparisonExpression, ExpressionType::kComparisonExpression>;
 using SomeExists = SomeExpressionNode<Exists, ExpressionType::kExists>;
+using SomeInTableQuery = SomeExpressionNode<InTableQuery, ExpressionType::kInTableQuery>;
+using SomeInValueList = SomeExpressionNode<InValueList, ExpressionType::kInValueList>;
 using SomeLogicalAnd = SomeExpressionNode<LogicalAnd, ExpressionType::kLogicalAnd>;
 using SomeLogicalNot = SomeExpressionNode<LogicalNot, ExpressionType::kLogicalNot>;
 using SomeLogicalOr = SomeExpressionNode<LogicalOr, ExpressionType::kLogicalOr>;
@@ -128,6 +132,8 @@ using SomeNamedExpression = SomeExpressionNode<NamedExpression,
 using SomePredicate = SomeExpressionNode<Predicate,
                                          ExpressionType::kComparisonExpression,
                                          ExpressionType::kExists,
+                                         ExpressionType::kInTableQuery,
+                                         ExpressionType::kInValueList,
                                          ExpressionType::kLogicalAnd,
                                          ExpressionType::kLogicalNot,
                                          ExpressionType::kLogicalOr,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/resolver/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/CMakeLists.txt b/query_optimizer/resolver/CMakeLists.txt
index 72f5bd7..f8ffa72 100644
--- a/query_optimizer/resolver/CMakeLists.txt
+++ b/query_optimizer/resolver/CMakeLists.txt
@@ -1,5 +1,7 @@
 #   Copyright 2011-2015 Quickstep Technologies LLC.
 #   Copyright 2015 Pivotal Software, Inc.
+#   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+#     University of Wisconsin—Madison.
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -49,6 +51,7 @@ target_link_libraries(quickstep_queryoptimizer_resolver_Resolver
                       quickstep_parser_ParseOrderBy
                       quickstep_parser_ParsePredicate
                       quickstep_parser_ParsePredicateExists
+                      quickstep_parser_ParsePredicateInTableQuery
                       quickstep_parser_ParseSelect
                       quickstep_parser_ParseSelectionClause
                       quickstep_parser_ParseSimpleTableReference
@@ -68,6 +71,8 @@ target_link_libraries(quickstep_queryoptimizer_resolver_Resolver
                       quickstep_queryoptimizer_expressions_Exists
                       quickstep_queryoptimizer_expressions_ExprId
                       quickstep_queryoptimizer_expressions_ExpressionUtil
+                      quickstep_queryoptimizer_expressions_InTableQuery
+                      quickstep_queryoptimizer_expressions_InValueList
                       quickstep_queryoptimizer_expressions_LogicalAnd
                       quickstep_queryoptimizer_expressions_LogicalNot
                       quickstep_queryoptimizer_expressions_LogicalOr

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/resolver/Resolver.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp
index f44aae8..8323c33 100644
--- a/query_optimizer/resolver/Resolver.cpp
+++ b/query_optimizer/resolver/Resolver.cpp
@@ -47,6 +47,7 @@
 #include "parser/ParseOrderBy.hpp"
 #include "parser/ParsePredicate.hpp"
 #include "parser/ParsePredicateExists.hpp"
+#include "parser/ParsePredicateInTableQuery.hpp"
 #include "parser/ParseSelect.hpp"
 #include "parser/ParseSelectionClause.hpp"
 #include "parser/ParseSimpleTableReference.hpp"
@@ -66,6 +67,8 @@
 #include "query_optimizer/expressions/Exists.hpp"
 #include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/ExpressionUtil.hpp"
+#include "query_optimizer/expressions/InTableQuery.hpp"
+#include "query_optimizer/expressions/InValueList.hpp"
 #include "query_optimizer/expressions/LogicalAnd.hpp"
 #include "query_optimizer/expressions/LogicalNot.hpp"
 #include "query_optimizer/expressions/LogicalOr.hpp"
@@ -115,6 +118,8 @@
 #include "utility/SqlError.hpp"
 #include "utility/StringUtil.hpp"
 
+#include "glog/logging.h"
+
 namespace quickstep {
 namespace optimizer {
 namespace resolver {
@@ -1188,13 +1193,21 @@ L::LogicalPtr Resolver::resolveSelect(
 E::SubqueryExpressionPtr Resolver::resolveSubqueryExpression(
     const ParseSubqueryExpression &parse_subquery_expression,
     const std::vector<const Type*> *type_hints,
-    ExpressionResolutionInfo *expression_resolution_info) {
+    ExpressionResolutionInfo *expression_resolution_info,
+    const bool has_single_column) {
   L::LogicalPtr logical_subquery =
       resolveSelect(*parse_subquery_expression.query(),
                     "" /* select_name */,
                     type_hints,
                     &expression_resolution_info->name_resolver);
 
+  // Raise SQL error if the subquery is expected to return only one column but
+  // it returns multiple columns.
+  if (has_single_column && logical_subquery->getOutputAttributes().size() > 1u) {
+    THROW_SQL_ERROR_AT(&parse_subquery_expression)
+        << "Subquery must return exactly one column";
+  }
+
   if (!context_->has_nested_queries()) {
     context_->set_has_nested_queries();
   }
@@ -2523,7 +2536,74 @@ E::PredicatePtr Resolver::resolvePredicate(
       return E::Exists::Create(
           resolveSubqueryExpression(*exists.subquery(),
                                     nullptr /* type_hints */,
-                                    expression_resolution_info));
+                                    expression_resolution_info,
+                                    false /* has_single_column */));
+    }
+    case ParsePredicate::kInTableQuery: {
+      const ParsePredicateInTableQuery &in_table_query =
+          static_cast<const ParsePredicateInTableQuery&>(parse_predicate);
+
+      ExpressionResolutionInfo test_expr_resolution_info(*expression_resolution_info);
+      const E::ScalarPtr test_expression =
+          resolveExpression(*in_table_query.test_expression(),
+                            nullptr /* type_hint */,
+                            &test_expr_resolution_info);
+      if (test_expr_resolution_info.hasAggregate() && !expression_resolution_info->hasAggregate()) {
+        expression_resolution_info->parse_aggregate_expression =
+            test_expr_resolution_info.parse_aggregate_expression;
+      }
+
+      ExpressionResolutionInfo table_query_resolution_info(*expression_resolution_info);
+      const std::vector<const Type*> type_hints = { &test_expression->getValueType() };
+      const E::SubqueryExpressionPtr table_query =
+          resolveSubqueryExpression(*in_table_query.table_query(),
+                                    &type_hints,
+                                    &table_query_resolution_info,
+                                    true /* has_single_column */);
+      return E::InTableQuery::Create(test_expression,
+                                     table_query);
+    }
+    case ParsePredicate::kInValueList: {
+      const ParsePredicateInValueList &in_value_list =
+          static_cast<const ParsePredicateInValueList&>(parse_predicate);
+
+      ExpressionResolutionInfo test_expr_resolution_info(*expression_resolution_info);
+      const E::ScalarPtr test_expression =
+          resolveExpression(*in_value_list.test_expression(),
+                            nullptr /* type_hint */,
+                            &test_expr_resolution_info);
+      if (test_expr_resolution_info.hasAggregate() && !expression_resolution_info->hasAggregate()) {
+        expression_resolution_info->parse_aggregate_expression =
+            test_expr_resolution_info.parse_aggregate_expression;
+      }
+
+      std::vector<E::ScalarPtr> match_expressions;
+      for (const ParseExpression &parse_match_expression : *in_value_list.value_list()) {
+        ExpressionResolutionInfo match_expr_resolution_info(*expression_resolution_info);
+        E::ScalarPtr match_expression =
+            resolveExpression(parse_match_expression,
+                              &test_expression->getValueType(),
+                              &match_expr_resolution_info);
+
+        const Comparison &equality_comparison =
+            ComparisonFactory::GetComparison(ComparisonID::kEqual);
+        if (!equality_comparison.canCompareTypes(match_expression->getValueType(),
+                                                 test_expression->getValueType())) {
+          THROW_SQL_ERROR_AT(&parse_match_expression)
+              << "The value expression has the type "
+              << match_expression->getValueType().getName()
+              << ", which cannot be compared with the type of the test expression "
+              << test_expression->getValueType().getName();
+        }
+
+        if (match_expr_resolution_info.hasAggregate() && !expression_resolution_info->hasAggregate()) {
+          expression_resolution_info->parse_aggregate_expression =
+              match_expr_resolution_info.parse_aggregate_expression;
+        }
+        match_expressions.emplace_back(match_expression);
+      }
+      return E::InValueList::Create(test_expression,
+                                    match_expressions);
     }
     default:
       LOG(FATAL) << "Unknown predicate: " << parse_predicate.toString();

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/resolver/Resolver.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.hpp b/query_optimizer/resolver/Resolver.hpp
index 39b5388..31afe18 100644
--- a/query_optimizer/resolver/Resolver.hpp
+++ b/query_optimizer/resolver/Resolver.hpp
@@ -445,11 +445,14 @@ class Resolver {
    * @param type_hints The type hints for output columns by the subquery.
    * @param expression_resolution_info Resolution info that contains the name
    *        resolver and info to be updated after resolution.
+   * @param has_single_column True if the subquery is expected to return only
+   *        one column in the result.
    */
   expressions::SubqueryExpressionPtr resolveSubqueryExpression(
       const ParseSubqueryExpression &parse_subquery_expression,
       const std::vector<const Type*> *type_hints,
-      ExpressionResolutionInfo *expression_resolution_info);
+      ExpressionResolutionInfo *expression_resolution_info,
+      const bool has_single_column);
 
   /**
    * @brief Resolves a relation name to a pointer to the corresponding

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/rules/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/CMakeLists.txt b/query_optimizer/rules/CMakeLists.txt
index 03dcc50..3461a5e 100644
--- a/query_optimizer/rules/CMakeLists.txt
+++ b/query_optimizer/rules/CMakeLists.txt
@@ -118,6 +118,7 @@ target_link_libraries(quickstep_queryoptimizer_rules_UnnestSubqueries
                       quickstep_queryoptimizer_expressions_Expression
                       quickstep_queryoptimizer_expressions_ExpressionType
                       quickstep_queryoptimizer_expressions_ExpressionUtil
+                      quickstep_queryoptimizer_expressions_InTableQuery
                       quickstep_queryoptimizer_expressions_LogicalAnd
                       quickstep_queryoptimizer_expressions_LogicalNot
                       quickstep_queryoptimizer_expressions_LogicalOr
@@ -136,6 +137,7 @@ target_link_libraries(quickstep_queryoptimizer_rules_UnnestSubqueries
                       quickstep_queryoptimizer_rules_BottomUpRule
                       quickstep_queryoptimizer_rules_Rule
                       quickstep_types_operations_comparisons_Comparison
+                      quickstep_types_operations_comparisons_ComparisonFactory
                       quickstep_types_operations_comparisons_ComparisonID
                       quickstep_utility_Macros
                       quickstep_utility_SqlError)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/rules/UnnestSubqueries.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/UnnestSubqueries.cpp b/query_optimizer/rules/UnnestSubqueries.cpp
index 2dca36e..7852577 100644
--- a/query_optimizer/rules/UnnestSubqueries.cpp
+++ b/query_optimizer/rules/UnnestSubqueries.cpp
@@ -29,6 +29,7 @@
 #include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/ExpressionType.hpp"
 #include "query_optimizer/expressions/ExpressionUtil.hpp"
+#include "query_optimizer/expressions/InTableQuery.hpp"
 #include "query_optimizer/expressions/LogicalAnd.hpp"
 #include "query_optimizer/expressions/LogicalNot.hpp"
 #include "query_optimizer/expressions/LogicalOr.hpp"
@@ -45,6 +46,7 @@
 #include "query_optimizer/logical/TopLevelPlan.hpp"
 #include "query_optimizer/rules/Rule.hpp"
 #include "types/operations/comparisons/Comparison.hpp"
+#include "types/operations/comparisons/ComparisonFactory.hpp"
 #include "types/operations/comparisons/ComparisonID.hpp"
 #include "utility/SqlError.hpp"
 
@@ -300,6 +302,7 @@ E::ExpressionPtr UnnestSubqueriesForNonRootLogical::eliminateOuterAttributeRefer
     std::vector<E::AttributeReferencePtr> *probe_join_attributes,
     std::vector<E::AttributeReferencePtr> *build_join_attributes,
     std::vector<E::PredicatePtr> *non_hash_join_predicates) {
+  DCHECK(expression->getExpressionType() != E::ExpressionType::kInTableQuery);
   DCHECK(expression->getExpressionType() != E::ExpressionType::kExists);
   DCHECK(expression->getExpressionType() != E::ExpressionType::kSubqueryExpression);
 
@@ -569,6 +572,13 @@ E::ExpressionPtr UnnestSubqueriesForExpession::applyInternal(
       transformExists(static_cast<const E::Exists&>(*node));
       return E::ExpressionPtr();
     }
+    case E::ExpressionType::kInTableQuery: {
+      if (!allow_exists_or_in) {
+        THROW_SQL_ERROR() << "IN(table query) can only appear in (un-nested) NOT, AND or by itself";
+      }
+      transformInTableQuery(static_cast<const E::InTableQuery&>(*node));
+      return E::ExpressionPtr();
+    }
     case E::ExpressionType::kLogicalNot: {
       const E::LogicalNot &logical_not = static_cast<const E::LogicalNot&>(*node);
       const E::PredicatePtr &operand = logical_not.operand();
@@ -579,6 +589,13 @@ E::ExpressionPtr UnnestSubqueriesForExpession::applyInternal(
         transformExists(static_cast<const E::Exists&>(*operand));
         correlated_query_info_vec_->back().join_type = CorrelatedQueryInfo::JoinType::kLeftAntiJoin;
         return E::PredicatePtr();
+      } else if (operand->getExpressionType() == E::ExpressionType::kInTableQuery) {
+        if (!allow_exists_or_in) {
+          THROW_SQL_ERROR() << "IN(table query) can only appear in (un-nested) NOT, AND or by itself";
+        }
+        transformInTableQuery(static_cast<const E::InTableQuery&>(*operand));
+        correlated_query_info_vec_->back().join_type = CorrelatedQueryInfo::JoinType::kLeftAntiJoin;
+        return E::PredicatePtr();
       }
       const E::ExpressionPtr new_operand =
           applyInternal(false /* allow_exists_or_in */,
@@ -688,6 +705,48 @@ void UnnestSubqueriesForExpession::transformExists(
                                            std::move(non_hash_join_predicates));
 }
 
+void UnnestSubqueriesForExpession::transformInTableQuery(
+    const E::InTableQuery &in_table_query) {
+  std::vector<E::AttributeReferencePtr> probe_join_attributes;
+  std::vector<E::AttributeReferencePtr> build_join_attributes;
+  std::vector<E::PredicatePtr> non_hash_join_predicates;
+  UnnestSubqueriesForNonRootLogical unnest_logical_rule(false,  // scalar_query
+                                                        visible_attributes_from_outer_query_,
+                                                        context_,
+                                                        uncorrelated_subqueries_,
+                                                        &probe_join_attributes,
+                                                        &build_join_attributes,
+                                                        &non_hash_join_predicates);
+  const L::LogicalPtr subquery = in_table_query.table_query()->subquery();
+  const L::LogicalPtr new_subquery = unnest_logical_rule.apply(subquery);
+
+  DCHECK(!new_subquery->getOutputAttributes().empty());
+  const E::AttributeReferencePtr join_attr_in_subquery = subquery->getOutputAttributes()[0];
+
+  E::AttributeReferencePtr test_attribute;
+  if (E::SomeAttributeReference::MatchesWithConditionalCast(in_table_query.test_expression(),
+                                                            &test_attribute)) {
+    probe_join_attributes.emplace_back(test_attribute);
+    build_join_attributes.emplace_back(join_attr_in_subquery);
+  } else {
+    if (!probe_join_attributes.empty()) {
+      non_hash_join_predicates.emplace_back(
+          E::ComparisonExpression::Create(ComparisonFactory::GetComparison(ComparisonID::kEqual),
+                                          in_table_query.test_expression(),
+                                          join_attr_in_subquery));
+    } else {
+      // TODO(qzeng): We can actually add a project to precompute the test expression.
+      THROW_SQL_ERROR() << "Cannot find an equality join predicate for IN";
+    }
+  }
+
+  correlated_query_info_vec_->emplace_back(CorrelatedQueryInfo::JoinType::kLeftSemiJoin,
+                                           new_subquery,
+                                           std::move(probe_join_attributes),
+                                           std::move(build_join_attributes),
+                                           std::move(non_hash_join_predicates));
+}
+
 E::ExpressionPtr DeOuterAttributeReference::applyToNode(const E::ExpressionPtr &input) {
   E::AttributeReferencePtr attr;
   if (E::SomeAttributeReference::MatchesWithConditionalCast(input, &attr) &&

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/rules/UnnestSubqueries.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/rules/UnnestSubqueries.hpp b/query_optimizer/rules/UnnestSubqueries.hpp
index 1ab48ac..d51dfd5 100644
--- a/query_optimizer/rules/UnnestSubqueries.hpp
+++ b/query_optimizer/rules/UnnestSubqueries.hpp
@@ -41,6 +41,7 @@ class OptimizerContext;
 namespace expressions {
 
 class Exists;
+class InTableQuery;
 
 }
 
@@ -179,8 +180,22 @@ class UnnestSubqueriesForExpession : public Rule<expressions::Expression> {
       const bool allow_exists_or_in,
       const expressions::ExpressionPtr &node);
 
+  /**
+   * @brief Transform an EXIST predicate into a HashLeftSemiJoin and store the
+   *        transformed results into correlated_query_info_vec_
+   *
+   * @param exists_predicate The EXISTS predicate to be transformed.
+   */
   void transformExists(const expressions::Exists &exists_predicate);
 
+  /**
+   * @brief Transform an IN predicate into a HashLeftSemiJoin and store the
+   *        transformed results into correlated_query_info_vec_
+   *
+   * @param in_table_query The IN predicate to be transformed.
+   */
+  void transformInTableQuery(const expressions::InTableQuery &in_table_query);
+
   OptimizerContext *context_;
   std::unordered_map<expressions::ExprId, logical::LogicalPtr> *uncorrelated_subqueries_;
   std::vector<CorrelatedQueryInfo> *correlated_query_info_vec_;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/tests/execution_generator/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/execution_generator/Select.test b/query_optimizer/tests/execution_generator/Select.test
index 9bfa27c..0618ae2 100644
--- a/query_optimizer/tests/execution_generator/Select.test
+++ b/query_optimizer/tests/execution_generator/Select.test
@@ -764,6 +764,62 @@ WHERE
 +-----------+
 ==
 
+# IN predicate
+SELECT *
+FROM generate_series(1, 5) AS gs(i)
+WHERE i IN (2, 4);
+--
++-----------+
+|i          |
++-----------+
+|          2|
+|          4|
++-----------+
+==
+
+SELECT *
+FROM generate_series(1, 5) AS gs(i)
+WHERE i NOT IN (2, 4);
+--
++-----------+
+|i          |
++-----------+
+|          1|
+|          3|
+|          5|
++-----------+
+==
+
+SELECT *
+FROM generate_series(1, 5) AS gs(i)
+WHERE i NOT IN (i*i-6, CASE WHEN i < 3 THEN 1 ELSE 4 END);
+--
++-----------+
+|i          |
++-----------+
+|          2|
+|          5|
++-----------+
+==
+
+SELECT *
+FROM generate_series(1, 10) AS gs(i)
+WHERE i NOT IN (
+  SELECT *
+  FROM generate_series(2, 10, 2)
+);
+--
++-----------+
+|i          |
++-----------+
+|          1|
+|          3|
+|          5|
+|          7|
+|          9|
++-----------+
+==
+
 # TODO(team): Support uncorrelated queries.
 # SELECT COUNT(*)
 # FROM test

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/0fd8c039/query_optimizer/tests/logical_generator/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/logical_generator/Select.test b/query_optimizer/tests/logical_generator/Select.test
index a7a9cf8..c6d4201 100644
--- a/query_optimizer/tests/logical_generator/Select.test
+++ b/query_optimizer/tests/logical_generator/Select.test
@@ -720,3 +720,179 @@ TopLevelPlan
 |   +-AttributeReference[id=1,name=i,relation=,type=Int]
 +-output_attributes=
   +-AttributeReference[id=1,name=i,relation=,type=Int]
+==
+
+# IN predicate
+SELECT char_col
+FROM test
+WHERE int_col IN (1, 2, 3);
+--
+TopLevelPlan
++-plan=Project
+| +-input=Filter
+| | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   type=VarChar(20) NULL]
+| | +-filter_predicate=InValueList
+| |   +-test_expression=AttributeReference[id=0,name=int_col,relation=test,
+| |   | type=Int NULL]
+| |   +-match_expressions=
+| |     +-Literal[value=1,type=Int]
+| |     +-Literal[value=2,type=Int]
+| |     +-Literal[value=3,type=Int]
+| +-project_list=
+|   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
++-output_attributes=
+  +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+==
+
+SELECT char_col
+FROM test
+WHERE int_col*2 NOT IN (
+        long_col+1,
+        CASE WHEN float_col > 0 THEN 1
+             ELSE double_col END);
+--
+TopLevelPlan
++-plan=Project
+| +-input=Filter
+| | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   type=VarChar(20) NULL]
+| | +-filter_predicate=NOT
+| |   +-InValueList
+| |     +-test_expression=Multiply
+| |     | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| |     | +-Literal[value=2,type=Int]
+| |     +-match_expressions=
+| |       +-Add
+| |       | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| |       | +-Literal[value=1,type=Int]
+| |       +-SearchedCase
+| |         +-else_result_expression=AttributeReference[id=3,name=double_col,
+| |         | relation=test,type=Double NULL]
+| |         +-condition_perdicates=
+| |         | +-Greater
+| |         |   +-AttributeReference[id=2,name=float_col,relation=test,
+| |         |   | type=Float]
+| |         |   +-Literal[value=0,type=Int]
+| |         +-conditional_result_expressions=
+| |           +-Cast[target_type=Double NULL]
+| |             +-operand=Literal[value=1,type=Int]
+| +-project_list=
+|   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
++-output_attributes=
+  +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+==
+
+SELECT char_col
+FROM test
+WHERE int_col IN (
+  SELECT SUM(long_col) - 10
+  FROM test
+  GROUP BY vchar_col
+);
+--
+TopLevelPlan
++-plan=Project
+| +-input=HashLeftSemiJoin
+| | +-left=TableReference[relation_name=Test,relation_alias=test]
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   type=VarChar(20) NULL]
+| | +-right=Project
+| | | +-input=Aggregate
+| | | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | | +-AttributeReference[id=6,name=int_col,relation=test,type=Int NULL]
+| | | | | +-AttributeReference[id=7,name=long_col,relation=test,type=Long]
+| | | | | +-AttributeReference[id=8,name=float_col,relation=test,type=Float]
+| | | | | +-AttributeReference[id=9,name=double_col,relation=test,
+| | | | | | type=Double NULL]
+| | | | | +-AttributeReference[id=10,name=char_col,relation=test,type=Char(20)]
+| | | | | +-AttributeReference[id=11,name=vchar_col,relation=test,
+| | | | |   type=VarChar(20) NULL]
+| | | | +-grouping_expressions=
+| | | | | +-AttributeReference[id=11,name=vchar_col,relation=test,
+| | | | |   type=VarChar(20) NULL]
+| | | | +-aggregate_expressions=
+| | | |   +-Alias[id=12,name=,alias=$aggregate0,relation=$aggregate,
+| | | |     type=Long NULL]
+| | | |     +-AggregateFunction[function=SUM]
+| | | |       +-AttributeReference[id=7,name=long_col,relation=test,type=Long]
+| | | +-project_list=
+| | |   +-Alias[id=13,name=,alias=(SUM(long_col)-10),relation=,type=Long NULL]
+| | |     +-Subtract
+| | |       +-AttributeReference[id=12,name=,alias=$aggregate0,
+| | |       | relation=$aggregate,type=Long NULL]
+| | |       +-Literal[value=10,type=Int]
+| | +-left_join_attributes=
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | +-right_join_attributes=
+| |   +-AttributeReference[id=13,name=,alias=(SUM(long_col)-10),relation=,
+| |     type=Long NULL]
+| +-project_list=
+|   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
++-output_attributes=
+  +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+==
+
+SELECT char_col
+FROM test
+WHERE int_col NOT IN (
+  SELECT long_col
+  FROM test
+  WHERE long_col IN (1, 2)
+);
+--
+TopLevelPlan
++-plan=Project
+| +-input=HashLeftAntiJoin
+| | +-left=TableReference[relation_name=Test,relation_alias=test]
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   type=VarChar(20) NULL]
+| | +-right=Project
+| | | +-input=Filter
+| | | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | | +-AttributeReference[id=6,name=int_col,relation=test,type=Int NULL]
+| | | | | +-AttributeReference[id=7,name=long_col,relation=test,type=Long]
+| | | | | +-AttributeReference[id=8,name=float_col,relation=test,type=Float]
+| | | | | +-AttributeReference[id=9,name=double_col,relation=test,
+| | | | | | type=Double NULL]
+| | | | | +-AttributeReference[id=10,name=char_col,relation=test,type=Char(20)]
+| | | | | +-AttributeReference[id=11,name=vchar_col,relation=test,
+| | | | |   type=VarChar(20) NULL]
+| | | | +-filter_predicate=InValueList
+| | | |   +-test_expression=AttributeReference[id=7,name=long_col,relation=test,
+| | | |   | type=Long]
+| | | |   +-match_expressions=
+| | | |     +-Literal[value=1,type=Long]
+| | | |     +-Literal[value=2,type=Long]
+| | | +-project_list=
+| | |   +-AttributeReference[id=7,name=long_col,relation=test,type=Long]
+| | +-left_join_attributes=
+| | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | +-right_join_attributes=
+| |   +-AttributeReference[id=7,name=long_col,relation=test,type=Long]
+| +-project_list=
+|   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
++-output_attributes=
+  +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]