You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2017/03/21 22:36:30 UTC

[6/7] incubator-impala git commit: IMPALA-3586: Implement union passthrough

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a50c3440/testdata/workloads/functional-planner/queries/PlannerTest/union.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/union.test b/testdata/workloads/functional-planner/queries/PlannerTest/union.test
index 4baf6fe..b2368be 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/union.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/union.test
@@ -18,6 +18,7 @@ PLAN-ROOT SINK
 |     partitions=1/4 files=1 size=1.57KB
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypes]
 |     partitions=2/24 files=2 size=40.32KB
@@ -41,6 +42,7 @@ PLAN-ROOT SINK
 |     partitions=1/4 files=1 size=1.57KB
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypes]
 |     partitions=2/24 files=2 size=40.32KB
@@ -60,6 +62,7 @@ select * from functional.alltypestiny where year=2009 and month=2
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -82,6 +85,7 @@ PLAN-ROOT SINK
 04:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -102,10 +106,7 @@ select * from functional.alltypestiny where year=2009 and month=2 limit 1
 PLAN-ROOT SINK
 |
 00:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|     limit: 1
+|  pass-through-operands: 01,04
 |
 |--03:TOP-N [LIMIT=1]
 |  |  order by: int_col ASC
@@ -113,6 +114,10 @@ PLAN-ROOT SINK
 |  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
+|--04:SCAN HDFS [functional.alltypestiny]
+|     partitions=1/4 files=1 size=115B
+|     limit: 1
+|
 01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
    limit: 1
@@ -127,15 +132,9 @@ NODE 4:
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: 05,06
 |
-|--07:EXCHANGE [UNPARTITIONED]
-|  |  limit: 1
-|  |
-|  04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|     limit: 1
-|
-|--06:MERGING-EXCHANGE [UNPARTITIONED]
+|--07:MERGING-EXCHANGE [UNPARTITIONED]
 |  |  order by: int_col ASC
 |  |  limit: 1
 |  |
@@ -145,6 +144,13 @@ PLAN-ROOT SINK
 |  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
+|--06:EXCHANGE [UNPARTITIONED]
+|  |  limit: 1
+|  |
+|  04:SCAN HDFS [functional.alltypestiny]
+|     partitions=1/4 files=1 size=115B
+|     limit: 1
+|
 05:EXCHANGE [UNPARTITIONED]
 |  limit: 1
 |
@@ -165,6 +171,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -195,6 +202,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -218,6 +226,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -236,6 +245,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -259,6 +269,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -285,6 +296,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -312,6 +324,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -352,6 +365,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -381,11 +395,13 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC, smallint_col ASC
 |
 04:UNION
+|  pass-through-operands: all
 |
 |--03:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  00:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--02:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -418,27 +434,29 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC, smallint_col ASC
 |
 04:UNION
+|  pass-through-operands: all
 |
-|--06:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--05:SCAN HDFS [functional.alltypestiny]
+|--09:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  03:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  00:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--02:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-09:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-03:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-00:UNION
-|
-|--02:SCAN HDFS [functional.alltypestiny]
+|--06:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-01:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Mixed UNION ALL/DISTINCT, no nested unions, with order by and limit
@@ -457,11 +475,13 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC, smallint_col ASC
 |
 05:UNION
+|  pass-through-operands: all
 |
 |--04:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  00:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--03:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -494,27 +514,29 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC, smallint_col ASC
 |
 05:UNION
+|  pass-through-operands: all
 |
-|--06:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-09:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-04:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-00:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--02:SCAN HDFS [functional.alltypestiny]
+|--09:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  04:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  00:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  |--02:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-01:SCAN HDFS [functional.alltypestiny]
+06:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: Only UNION ALL, first operand is nested
@@ -527,6 +549,7 @@ select * from functional.alltypestiny where year=2009 and month=1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -549,6 +572,7 @@ PLAN-ROOT SINK
 04:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -569,6 +593,7 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -591,6 +616,7 @@ PLAN-ROOT SINK
 04:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -614,6 +640,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -644,6 +671,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -667,6 +695,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -697,6 +726,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -718,6 +748,7 @@ select * from functional.alltypestiny where year=2009 and month=1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -726,6 +757,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 01:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -745,6 +777,7 @@ PLAN-ROOT SINK
 08:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -758,6 +791,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 01:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -776,11 +810,13 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  02:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--04:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -803,24 +839,26 @@ PLAN-ROOT SINK
 08:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-07:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-06:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-05:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
+|--07:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  06:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  05:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  02:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--04:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-03:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION ALL absorbs the children but not directly the operands
@@ -836,6 +874,7 @@ select * from functional.alltypestiny where year=2009 and month=1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--06:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -844,6 +883,7 @@ PLAN-ROOT SINK
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  02:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--04:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -868,27 +908,29 @@ PLAN-ROOT SINK
 09:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--06:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-08:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-07:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-05:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
+|--08:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  07:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  05:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  02:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--04:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-03:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION ALL absorbs the children but not directly the operands
@@ -904,11 +946,13 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--06:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  03:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--05:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -936,27 +980,29 @@ PLAN-ROOT SINK
 09:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
-|--02:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--01:SCAN HDFS [functional.alltypestiny]
+|--08:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  07:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  06:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  03:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--05:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-08:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-07:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-06:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-03:UNION
-|
-|--05:SCAN HDFS [functional.alltypestiny]
+|--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-04:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION ALL doesn't absorb the children of a nested union
@@ -973,14 +1019,17 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--06:UNION
+|  |  pass-through-operands: all
 |  |  limit: 10
 |  |
 |  |--05:AGGREGATE [FINALIZE]
 |  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |  |
 |  |  02:UNION
+|  |  |  pass-through-operands: all
 |  |  |
 |  |  |--04:SCAN HDFS [functional.alltypestiny]
 |  |  |     partitions=1/4 files=1 size=115B
@@ -1008,35 +1057,38 @@ PLAN-ROOT SINK
 12:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-11:EXCHANGE [RANDOM]
-|
-10:EXCHANGE [UNPARTITIONED]
-|  limit: 10
-|
-06:UNION
-|  limit: 10
-|
-|--07:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-09:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-05:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
+|--11:EXCHANGE [RANDOM]
+|  |
+|  10:EXCHANGE [UNPARTITIONED]
+|  |  limit: 10
+|  |
+|  06:UNION
+|  |  pass-through-operands: all
+|  |  limit: 10
+|  |
+|  |--09:AGGREGATE [FINALIZE]
+|  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |  |
+|  |  08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |  |
+|  |  05:AGGREGATE [STREAMING]
+|  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |  |
+|  |  02:UNION
+|  |  |  pass-through-operands: all
+|  |  |
+|  |  |--04:SCAN HDFS [functional.alltypestiny]
+|  |  |     partitions=1/4 files=1 size=115B
+|  |  |
+|  |  03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  07:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-03:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION ALL doesn't absorb nested union with order by and limit,
@@ -1051,19 +1103,21 @@ select * from functional.alltypestiny where year=2009 and month=1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-04:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--04:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ---- SCANRANGELOCATIONS
 NODE 2:
@@ -1078,25 +1132,27 @@ PLAN-ROOT SINK
 08:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-07:EXCHANGE [RANDOM]
-|
-06:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-04:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--07:EXCHANGE [RANDOM]
+|  |
+|  06:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  order by: tinyint_col ASC
+|  |  limit: 3
+|  |
+|  04:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION ALL doesn't absorb nested union with order by and limit,
@@ -1111,11 +1167,13 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: 01
 |
 |--05:TOP-N [LIMIT=3]
 |  |  order by: tinyint_col ASC
 |  |
 |  02:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--04:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -1138,25 +1196,27 @@ PLAN-ROOT SINK
 08:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: 01
 |
-|--01:SCAN HDFS [functional.alltypestiny]
+|--07:EXCHANGE [RANDOM]
+|  |
+|  06:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  order by: tinyint_col ASC
+|  |  limit: 3
+|  |
+|  05:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  02:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--04:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-07:EXCHANGE [RANDOM]
-|
-06:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-05:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-03:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION DISTINCT absorbs nested union with ALL
@@ -1173,6 +1233,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1203,6 +1264,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1227,6 +1289,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1257,6 +1320,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1283,6 +1347,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1318,6 +1383,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1347,6 +1413,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1382,6 +1449,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1410,19 +1478,21 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-04:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--04:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ---- SCANRANGELOCATIONS
 NODE 2:
@@ -1445,25 +1515,27 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-08:EXCHANGE [RANDOM]
-|
-07:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-04:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--08:EXCHANGE [RANDOM]
+|  |
+|  07:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  order by: tinyint_col ASC
+|  |  limit: 3
+|  |
+|  04:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Union unnesting: UNION DISTINCT doesn't absorb nested union with order by and limit
@@ -1481,11 +1553,13 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 01
 |
 |--05:TOP-N [LIMIT=3]
 |  |  order by: tinyint_col ASC
 |  |
 |  02:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--04:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -1516,25 +1590,27 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 01
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-08:EXCHANGE [RANDOM]
-|
-07:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-05:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
+|--08:EXCHANGE [RANDOM]
+|  |
+|  07:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  order by: tinyint_col ASC
+|  |  limit: 3
+|  |
+|  05:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  02:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--04:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-03:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Complex union unnesting: Multiple levels of UNION ALL, fully unnestable
@@ -1551,6 +1627,7 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1583,6 +1660,7 @@ PLAN-ROOT SINK
 06:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1616,6 +1694,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1656,6 +1735,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -1687,11 +1767,13 @@ union all
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--10:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  02:UNION
+|  |  pass-through-operands: 03,04
 |  |
 |  |--09:TOP-N [LIMIT=3]
 |  |  |  order by: tinyint_col ASC
@@ -1700,6 +1782,7 @@ PLAN-ROOT SINK
 |  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |  |
 |  |  05:UNION
+|  |  |  pass-through-operands: all
 |  |  |
 |  |  |--07:SCAN HDFS [functional.alltypestiny]
 |  |  |     partitions=1/4 files=1 size=115B
@@ -1732,49 +1815,52 @@ PLAN-ROOT SINK
 17:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-16:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-15:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-10:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-02:UNION
-|
-|--04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--03:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-14:EXCHANGE [RANDOM]
-|
-13:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-09:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-12:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-11:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-08:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-05:UNION
-|
-|--07:SCAN HDFS [functional.alltypestiny]
+|--16:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  15:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  10:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  02:UNION
+|  |  pass-through-operands: 03,04
+|  |
+|  |--14:EXCHANGE [RANDOM]
+|  |  |
+|  |  13:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  |  order by: tinyint_col ASC
+|  |  |  limit: 3
+|  |  |
+|  |  09:TOP-N [LIMIT=3]
+|  |  |  order by: tinyint_col ASC
+|  |  |
+|  |  12:AGGREGATE [FINALIZE]
+|  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |  |
+|  |  11:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |  |
+|  |  08:AGGREGATE [STREAMING]
+|  |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |  |
+|  |  05:UNION
+|  |  |  pass-through-operands: all
+|  |  |
+|  |  |--07:SCAN HDFS [functional.alltypestiny]
+|  |  |     partitions=1/4 files=1 size=115B
+|  |  |
+|  |  06:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  |--04:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-06:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Complex union unnesting: Partially unnestable up to 1st level
@@ -1795,6 +1881,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 01,02,03
 |
 |--08:TOP-N [LIMIT=3]
 |  |  order by: tinyint_col ASC
@@ -1803,6 +1890,7 @@ PLAN-ROOT SINK
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  04:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--06:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=1/4 files=1 size=115B
@@ -1843,39 +1931,41 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 01,02,03
 |
-|--03:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--02:SCAN HDFS [functional.alltypestiny]
+|--13:EXCHANGE [RANDOM]
+|  |
+|  12:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  order by: tinyint_col ASC
+|  |  limit: 3
+|  |
+|  08:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  11:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  10:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  07:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  04:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--06:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  05:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-|--01:SCAN HDFS [functional.alltypestiny]
+|--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-13:EXCHANGE [RANDOM]
-|
-12:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-08:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-11:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-10:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-07:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-04:UNION
-|
-|--06:SCAN HDFS [functional.alltypestiny]
+|--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-05:SCAN HDFS [functional.alltypestiny]
+01:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // Complex union unnesting: Multiple nested unions to test all rules in a single query
@@ -1902,16 +1992,31 @@ union all
 PLAN-ROOT SINK
 |
 09:UNION
+|  pass-through-operands: 10,11,08
+|
+|--15:TOP-N [LIMIT=3]
+|  |  order by: tinyint_col ASC
+|  |
+|  12:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--14:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=0/4 files=0 size=0B
+|  |
+|  13:SCAN HDFS [functional.alltypestiny]
+|     partitions=1/4 files=1 size=115B
 |
 |--08:AGGREGATE [FINALIZE]
 |  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |  |
 |  00:UNION
+|  |  pass-through-operands: 01,02,03
 |  |
 |  |--07:TOP-N [LIMIT=3]
 |  |  |  order by: tinyint_col ASC
 |  |  |
 |  |  04:UNION
+|  |  |  pass-through-operands: all
 |  |  |
 |  |  |--06:SCAN HDFS [functional.alltypestiny]
 |  |  |     partitions=1/4 files=1 size=115B
@@ -1928,17 +2033,6 @@ PLAN-ROOT SINK
 |  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-|--15:TOP-N [LIMIT=3]
-|  |  order by: tinyint_col ASC
-|  |
-|  12:UNION
-|  |
-|  |--14:SCAN HDFS [functional.alltypestiny]
-|  |     partitions=0/4 files=0 size=0B
-|  |
-|  13:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
 |--11:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
@@ -1968,16 +2062,11 @@ PLAN-ROOT SINK
 22:EXCHANGE [UNPARTITIONED]
 |
 09:UNION
-|
-|--11:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--10:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
+|  pass-through-operands: 10,11,19
 |
 |--21:EXCHANGE [RANDOM]
 |  |
-|  16:MERGING-EXCHANGE [UNPARTITIONED]
+|  20:MERGING-EXCHANGE [UNPARTITIONED]
 |  |  order by: tinyint_col ASC
 |  |  limit: 3
 |  |
@@ -1985,6 +2074,7 @@ PLAN-ROOT SINK
 |  |  order by: tinyint_col ASC
 |  |
 |  12:UNION
+|  |  pass-through-operands: all
 |  |
 |  |--14:SCAN HDFS [functional.alltypestiny]
 |  |     partitions=0/4 files=0 size=0B
@@ -1992,40 +2082,48 @@ PLAN-ROOT SINK
 |  13:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-20:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-19:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-08:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-00:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--02:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-|--01:SCAN HDFS [functional.alltypestiny]
+|--19:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  18:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  08:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  00:UNION
+|  |  pass-through-operands: 01,02,03
+|  |
+|  |--17:EXCHANGE [RANDOM]
+|  |  |
+|  |  16:MERGING-EXCHANGE [UNPARTITIONED]
+|  |  |  order by: tinyint_col ASC
+|  |  |  limit: 3
+|  |  |
+|  |  07:TOP-N [LIMIT=3]
+|  |  |  order by: tinyint_col ASC
+|  |  |
+|  |  04:UNION
+|  |  |  pass-through-operands: all
+|  |  |
+|  |  |--06:SCAN HDFS [functional.alltypestiny]
+|  |  |     partitions=1/4 files=1 size=115B
+|  |  |
+|  |  05:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  |--02:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-18:EXCHANGE [RANDOM]
-|
-17:MERGING-EXCHANGE [UNPARTITIONED]
-|  order by: tinyint_col ASC
-|  limit: 3
-|
-07:TOP-N [LIMIT=3]
-|  order by: tinyint_col ASC
-|
-04:UNION
-|
-|--06:SCAN HDFS [functional.alltypestiny]
+|--11:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-05:SCAN HDFS [functional.alltypestiny]
+10:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // UNION ALL in subquery
@@ -2043,16 +2141,18 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC
 |
 00:UNION
+|  pass-through-operands: 04
 |
-|--04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+04:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ---- SCANRANGELOCATIONS
 NODE 2:
@@ -2072,16 +2172,18 @@ PLAN-ROOT SINK
 |  order by: tinyint_col ASC
 |
 00:UNION
+|  pass-through-operands: 04
 |
-|--04:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+04:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // UNION DISTINCT in subquery
@@ -2102,19 +2204,21 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-04:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--04:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ---- SCANRANGELOCATIONS
 NODE 2:
@@ -2142,24 +2246,26 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 05
 |
-|--05:SCAN HDFS [functional.alltypestiny]
-|     partitions=1/4 files=1 size=115B
-|
-09:AGGREGATE [FINALIZE]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
-|
-04:AGGREGATE [STREAMING]
-|  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
-|
-01:UNION
-|
-|--03:SCAN HDFS [functional.alltypestiny]
+|--09:AGGREGATE [FINALIZE]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  08:EXCHANGE [HASH(id,bool_col,tinyint_col,smallint_col,int_col,bigint_col,float_col,double_col,date_string_col,string_col,timestamp_col,year,month)]
+|  |
+|  04:AGGREGATE [STREAMING]
+|  |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
+|  |
+|  01:UNION
+|  |  pass-through-operands: all
+|  |
+|  |--03:SCAN HDFS [functional.alltypestiny]
+|  |     partitions=1/4 files=1 size=115B
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
 |
-02:SCAN HDFS [functional.alltypestiny]
+05:SCAN HDFS [functional.alltypestiny]
    partitions=1/4 files=1 size=115B
 ====
 // UNION ALL in subquery with a WHERE condition in the outer select.
@@ -2174,6 +2280,7 @@ where x.int_col < 5 and x.bool_col = false
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--04:AGGREGATE [FINALIZE]
 |  |  output: count(*)
@@ -2201,6 +2308,7 @@ PLAN-ROOT SINK
 09:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--08:AGGREGATE [FINALIZE]
 |  |  output: count:merge(*)
@@ -2282,12 +2390,14 @@ select int_col, string_col, bool_col, float_col from functional.alltypestiny
 PLAN-ROOT SINK
 |
 03:UNION
+|  pass-through-operands: all
 |
 |--02:AGGREGATE [FINALIZE]
 |  |  group by: 1, 'a', null, f
 |  |
 |  00:UNION
 |  |  constant-operands=2
+|  |  pass-through-operands: all
 |  |
 |  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=4/4 files=4 size=460B
@@ -2300,22 +2410,24 @@ PLAN-ROOT SINK
 07:EXCHANGE [UNPARTITIONED]
 |
 03:UNION
+|  pass-through-operands: all
 |
-|--04:SCAN HDFS [functional.alltypestiny]
+|--06:AGGREGATE [FINALIZE]
+|  |  group by: 1, 'a', null, f
+|  |
+|  05:EXCHANGE [HASH(1,'a',null,f)]
+|  |
+|  02:AGGREGATE [STREAMING]
+|  |  group by: 1, 'a', null, f
+|  |
+|  00:UNION
+|  |  constant-operands=2
+|  |  pass-through-operands: all
+|  |
+|  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=4/4 files=4 size=460B
 |
-06:AGGREGATE [FINALIZE]
-|  group by: 1, 'a', null, f
-|
-05:EXCHANGE [HASH(1,'a',null,f)]
-|
-02:AGGREGATE [STREAMING]
-|  group by: 1, 'a', null, f
-|
-00:UNION
-|  constant-operands=2
-|
-01:SCAN HDFS [functional.alltypestiny]
+04:SCAN HDFS [functional.alltypestiny]
    partitions=4/4 files=4 size=460B
 ====
 // UNION ALL/DISTINCT with mixed constant selects and non-constant selects and nested unions
@@ -2335,12 +2447,14 @@ PLAN-ROOT SINK
 |
 05:UNION
 |  constant-operands=1
+|  pass-through-operands: all
 |
 04:AGGREGATE [FINALIZE]
 |  group by: 500
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: 02
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -2357,6 +2471,7 @@ PLAN-ROOT SINK
 |
 05:UNION
 |  constant-operands=1
+|  pass-through-operands: all
 |
 09:AGGREGATE [FINALIZE]
 |  group by: 500
@@ -2368,6 +2483,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=2
+|  pass-through-operands: 07
 |
 |--03:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -2436,12 +2552,14 @@ select int_col, string_col, bool_col, float_col from functional.alltypessmall
 PLAN-ROOT SINK
 |
 03:UNION
+|  pass-through-operands: all
 |
 |--02:AGGREGATE [FINALIZE]
 |  |  group by: 1, 'a', null, f
 |  |
 |  00:UNION
 |  |  constant-operands=2
+|  |  pass-through-operands: all
 |  |
 |  01:SCAN HDFS [functional.alltypestiny]
 |     partitions=4/4 files=4 size=460B
@@ -2454,23 +2572,25 @@ PLAN-ROOT SINK
 07:EXCHANGE [UNPARTITIONED]
 |
 03:UNION
+|  pass-through-operands: all
 |
-|--04:SCAN HDFS [functional.alltypessmall]
-|     partitions=4/4 files=4 size=6.32KB
-|
-06:AGGREGATE [FINALIZE]
-|  group by: 1, 'a', null, f
-|
-05:EXCHANGE [HASH(1,'a',null,f)]
-|
-02:AGGREGATE [STREAMING]
-|  group by: 1, 'a', null, f
-|
-00:UNION
-|  constant-operands=2
+|--06:AGGREGATE [FINALIZE]
+|  |  group by: 1, 'a', null, f
+|  |
+|  05:EXCHANGE [HASH(1,'a',null,f)]
+|  |
+|  02:AGGREGATE [STREAMING]
+|  |  group by: 1, 'a', null, f
+|  |
+|  00:UNION
+|  |  constant-operands=2
+|  |  pass-through-operands: all
+|  |
+|  01:SCAN HDFS [functional.alltypestiny]
+|     partitions=4/4 files=4 size=460B
 |
-01:SCAN HDFS [functional.alltypestiny]
-   partitions=4/4 files=4 size=460B
+04:SCAN HDFS [functional.alltypessmall]
+   partitions=4/4 files=4 size=6.32KB
 ====
 # all union output slots are being materialized even though none is referenced by
 # the enclosing scope
@@ -2503,6 +2623,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=3
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypes]
 |     partitions=24/24 files=24 size=478.45KB
@@ -2530,6 +2651,7 @@ PLAN-ROOT SINK
 |
 00:UNION
 |  constant-operands=3
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypes]
 |     partitions=24/24 files=24 size=478.45KB
@@ -2540,7 +2662,7 @@ PLAN-ROOT SINK
 # UNION ALL in subquery with a WHERE condition in the outer select;
 # Where clause conjuncts are used as scan predicates and for partition pruning.
 select x.int_col, x.bool_col, x.month from
-  (select * from functional.alltypestiny where year=2009 
+  (select * from functional.alltypestiny where year=2009
    union all
    select * from functional.alltypestiny where year=2009) x
 where x.int_col < 5 and x.bool_col = false and x.month = 1
@@ -2548,6 +2670,7 @@ where x.int_col < 5 and x.bool_col = false and x.month = 1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -2562,6 +2685,7 @@ PLAN-ROOT SINK
 03:EXCHANGE [UNPARTITIONED]
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [functional.alltypestiny]
 |     partitions=1/4 files=1 size=115B
@@ -2656,9 +2780,6 @@ PLAN-ROOT SINK
 00:UNION
 |  constant-operands=1
 |
-|--01:SCAN HDFS [functional.alltypestiny]
-|     partitions=4/4 files=4 size=460B
-|
 |--06:HASH JOIN [INNER JOIN, PARTITIONED]
 |  |  hash predicates: a.id = b.id
 |  |  runtime filters: RF000 <- b.id
@@ -2674,18 +2795,21 @@ PLAN-ROOT SINK
 |     partitions=4/4 files=4 size=460B
 |     runtime filters: RF000 -> a.id
 |
-08:AGGREGATE [FINALIZE]
-|  output: sum:merge(int_col)
-|  group by: bigint_col
-|
-07:EXCHANGE [HASH(bigint_col)]
-|
-03:AGGREGATE [STREAMING]
-|  output: sum(int_col)
-|  group by: bigint_col
+|--08:AGGREGATE [FINALIZE]
+|  |  output: sum:merge(int_col)
+|  |  group by: bigint_col
+|  |
+|  07:EXCHANGE [HASH(bigint_col)]
+|  |
+|  03:AGGREGATE [STREAMING]
+|  |  output: sum(int_col)
+|  |  group by: bigint_col
+|  |
+|  02:SCAN HDFS [functional.alltypes]
+|     partitions=1/24 files=1 size=18.12KB
 |
-02:SCAN HDFS [functional.alltypes]
-   partitions=1/24 files=1 size=18.12KB
+01:SCAN HDFS [functional.alltypestiny]
+   partitions=4/4 files=4 size=460B
 ====
 # Test union merging only unpartitioned inputs.
 select count(id), sum(bigint_col) from functional.alltypes
@@ -2799,6 +2923,34 @@ PLAN-ROOT SINK
 00:UNION
 |  constant-operands=1
 |
+|--10:HASH JOIN [INNER JOIN, PARTITIONED]
+|  |  hash predicates: a.id = b.id
+|  |  runtime filters: RF000 <- b.id
+|  |
+|  |--17:EXCHANGE [HASH(b.id)]
+|  |  |
+|  |  09:SCAN HDFS [functional.alltypestiny b]
+|  |     partitions=4/4 files=4 size=460B
+|  |
+|  16:EXCHANGE [HASH(a.id)]
+|  |
+|  08:SCAN HDFS [functional.alltypestiny a]
+|     partitions=4/4 files=4 size=460B
+|     runtime filters: RF000 -> a.id
+|
+|--15:AGGREGATE [FINALIZE]
+|  |  output: sum:merge(int_col)
+|  |  group by: bigint_col
+|  |
+|  14:EXCHANGE [HASH(bigint_col)]
+|  |
+|  07:AGGREGATE [STREAMING]
+|  |  output: sum(int_col)
+|  |  group by: bigint_col
+|  |
+|  06:SCAN HDFS [functional.alltypes]
+|     partitions=1/24 files=1 size=18.12KB
+|
 |--05:SCAN HDFS [functional.alltypestiny]
 |     partitions=4/4 files=4 size=460B
 |
@@ -2814,46 +2966,18 @@ PLAN-ROOT SINK
 |  03:SCAN HDFS [functional.alltypessmall]
 |     partitions=4/4 files=4 size=6.32KB
 |
-|--18:EXCHANGE [RANDOM]
-|  |
-|  12:AGGREGATE [FINALIZE]
-|  |  output: count:merge(id), sum:merge(bigint_col)
-|  |
-|  11:EXCHANGE [UNPARTITIONED]
-|  |
-|  02:AGGREGATE
-|  |  output: count(id), sum(bigint_col)
-|  |
-|  01:SCAN HDFS [functional.alltypes]
-|     partitions=24/24 files=24 size=478.45KB
-|
-|--10:HASH JOIN [INNER JOIN, PARTITIONED]
-|  |  hash predicates: a.id = b.id
-|  |  runtime filters: RF000 <- b.id
-|  |
-|  |--17:EXCHANGE [HASH(b.id)]
-|  |  |
-|  |  09:SCAN HDFS [functional.alltypestiny b]
-|  |     partitions=4/4 files=4 size=460B
-|  |
-|  16:EXCHANGE [HASH(a.id)]
-|  |
-|  08:SCAN HDFS [functional.alltypestiny a]
-|     partitions=4/4 files=4 size=460B
-|     runtime filters: RF000 -> a.id
+18:EXCHANGE [RANDOM]
 |
-15:AGGREGATE [FINALIZE]
-|  output: sum:merge(int_col)
-|  group by: bigint_col
+12:AGGREGATE [FINALIZE]
+|  output: count:merge(id), sum:merge(bigint_col)
 |
-14:EXCHANGE [HASH(bigint_col)]
+11:EXCHANGE [UNPARTITIONED]
 |
-07:AGGREGATE [STREAMING]
-|  output: sum(int_col)
-|  group by: bigint_col
+02:AGGREGATE
+|  output: count(id), sum(bigint_col)
 |
-06:SCAN HDFS [functional.alltypes]
-   partitions=1/24 files=1 size=18.12KB
+01:SCAN HDFS [functional.alltypes]
+   partitions=24/24 files=24 size=478.45KB
 ====
 # IMPALA-3450: limits on union nodes are reflected in cardinality estimates. The test for
 # this is embedded in PlannerTestBase.java and is not visible in these plans, as they only
@@ -2863,6 +2987,7 @@ select * from tpch.lineitem UNION ALL (select * from tpch.lineitem) LIMIT 1
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: all
 |  limit: 1
 |
 |--02:SCAN HDFS [tpch.lineitem]
@@ -2880,6 +3005,7 @@ PLAN-ROOT SINK
 |  limit: 1
 |
 00:UNION
+|  pass-through-operands: all
 |
 |--02:SCAN HDFS [tpch.lineitem]
 |     partitions=1/1 files=1 size=718.94MB
@@ -2902,6 +3028,7 @@ where v.id < 10 and v.int_col > 20
 PLAN-ROOT SINK
 |
 00:UNION
+|  pass-through-operands: 01,02
 |
 |--08:SELECT
 |  |  predicates: id < 10, int_col > 20
@@ -2946,6 +3073,7 @@ PLAN-ROOT SINK
 |  group by: id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month
 |
 00:UNION
+|  pass-through-operands: 01,02
 |
 |--08:SELECT
 |  |  predicates: id < 10, int_col > 20
@@ -2973,3 +3101,117 @@ PLAN-ROOT SINK
    partitions=24/24 files=24 size=478.45KB
    predicates: functional.alltypes.id < 10, functional.alltypes.int_col > 20
 ====
+# IMPALA-3678: Both union operands produce rows with non-nullable slots which can be
+# passed through.
+select kudu_idx from functional_kudu.alltypesagg_idx limit 5
+union all
+select count(*) from functional.alltypestiny;
+---- PLAN
+PLAN-ROOT SINK
+|
+00:UNION
+|  pass-through-operands: all
+|
+|--03:AGGREGATE [FINALIZE]
+|  |  output: count(*)
+|  |
+|  02:SCAN HDFS [functional.alltypestiny]
+|     partitions=4/4 files=4 size=460B
+|
+01:SCAN KUDU [functional_kudu.alltypesagg_idx]
+   limit: 5
+====
+# IMPALA-3678: The Union operands that contain a join should not be passed through,
+# because the resulting row contains 2 tuples, instead of one. However, a semi join
+# outputs a row with only 1 tuple, so it should be passed through.
+select bigint_col from functional.alltypestiny
+union
+select t1.bigint_col from functional.alltypestiny t1 left semi join
+  functional.alltypes t2 on t1.bigint_col = t2.bigint_col
+union
+select t1.bigint_col from functional.alltypestiny t1 left join
+  functional.alltypes t2 on t1.bigint_col = t2.bigint_col
+union
+select t1.bigint_col from functional.alltypestiny t1 inner join
+  functional.alltypes t2 on t1.bigint_col = t2.bigint_col
+---- PLAN
+PLAN-ROOT SINK
+|
+11:AGGREGATE [FINALIZE]
+|  group by: bigint_col
+|
+00:UNION
+|  pass-through-operands: 01,04
+|
+|--10:HASH JOIN [INNER JOIN]
+|  |  hash predicates: t2.bigint_col = t1.bigint_col
+|  |  runtime filters: RF002 <- t1.bigint_col
+|  |
+|  |--08:SCAN HDFS [functional.alltypestiny t1]
+|  |     partitions=4/4 files=4 size=460B
+|  |
+|  09:SCAN HDFS [functional.alltypes t2]
+|     partitions=24/24 files=24 size=478.45KB
+|     runtime filters: RF002 -> t2.bigint_col
+|
+|--07:HASH JOIN [RIGHT OUTER JOIN]
+|  |  hash predicates: t2.bigint_col = t1.bigint_col
+|  |  runtime filters: RF001 <- t1.bigint_col
+|  |
+|  |--05:SCAN HDFS [functional.alltypestiny t1]
+|  |     partitions=4/4 files=4 size=460B
+|  |
+|  06:SCAN HDFS [functional.alltypes t2]
+|     partitions=24/24 files=24 size=478.45KB
+|     runtime filters: RF001 -> t2.bigint_col
+|
+|--04:HASH JOIN [RIGHT SEMI JOIN]
+|  |  hash predicates: t2.bigint_col = t1.bigint_col
+|  |  runtime filters: RF000 <- t1.bigint_col
+|  |
+|  |--02:SCAN HDFS [functional.alltypestiny t1]
+|  |     partitions=4/4 files=4 size=460B
+|  |
+|  03:SCAN HDFS [functional.alltypes t2]
+|     partitions=24/24 files=24 size=478.45KB
+|     runtime filters: RF000 -> t2.bigint_col
+|
+01:SCAN HDFS [functional.alltypestiny]
+   partitions=4/4 files=4 size=460B
+====
+# IMPALA-3678: union in a subplan - passthrough should be disabled.
+select count(c.c_custkey), count(v.tot_price)
+from tpch_nested_parquet.customer c, (
+  select sum(o_totalprice) tot_price from c.c_orders
+  union
+  select sum(o_totalprice) tot_price from c.c_orders) v;
+---- PLAN
+PLAN-ROOT SINK
+|
+10:AGGREGATE [FINALIZE]
+|  output: count(c.c_custkey), count(tot_price)
+|
+01:SUBPLAN
+|
+|--09:NESTED LOOP JOIN [CROSS JOIN]
+|  |
+|  |--02:SINGULAR ROW SRC
+|  |
+|  08:AGGREGATE [FINALIZE]
+|  |  group by: tot_price
+|  |
+|  03:UNION
+|  |
+|  |--07:AGGREGATE [FINALIZE]
+|  |  |  output: sum(o_totalprice)
+|  |  |
+|  |  06:UNNEST [c.c_orders]
+|  |
+|  05:AGGREGATE [FINALIZE]
+|  |  output: sum(o_totalprice)
+|  |
+|  04:UNNEST [c.c_orders]
+|
+00:SCAN HDFS [tpch_nested_parquet.customer c]
+   partitions=1/1 files=4 size=292.36MB
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a50c3440/testdata/workloads/functional-planner/queries/PlannerTest/with-clause.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/with-clause.test b/testdata/workloads/functional-planner/queries/PlannerTest/with-clause.test
index e0d2d8c..69105c7 100644
--- a/testdata/workloads/functional-planner/queries/PlannerTest/with-clause.test
+++ b/testdata/workloads/functional-planner/queries/PlannerTest/with-clause.test
@@ -68,18 +68,18 @@ PLAN-ROOT SINK
 |
 00:UNION
 |
-|--01:SCAN HDFS [functional.alltypes]
-|     partitions=24/24 files=24 size=478.45KB
-|
 |--05:EXCHANGE [RANDOM]
 |  |
 |  03:UNION
 |     constant-operands=2
 |
-04:EXCHANGE [RANDOM]
+|--04:EXCHANGE [RANDOM]
+|  |
+|  02:UNION
+|     constant-operands=1
 |
-02:UNION
-   constant-operands=1
+01:SCAN HDFS [functional.alltypes]
+   partitions=24/24 files=24 size=478.45KB
 ====
 # Multiple views in with-clause. All views are used in a join.
 with t1 as (select int_col x, bigint_col y from functional.alltypes),

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a50c3440/testdata/workloads/functional-query/queries/QueryTest/nested-types-subplan.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-query/queries/QueryTest/nested-types-subplan.test b/testdata/workloads/functional-query/queries/QueryTest/nested-types-subplan.test
index 168a6e3..fa494ab 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/nested-types-subplan.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/nested-types-subplan.test
@@ -576,3 +576,15 @@ where c_custkey = 1
 ---- TYPES
 BIGINT,BIGINT
 ====
+---- QUERY
+# IMPALA-3678: union in a subplan - passthrough should be disabled.
+select count(c.c_custkey), count(v.tot_price)
+from tpch_nested_parquet.customer c, (
+select sum(o_totalprice) tot_price from c.c_orders
+union
+select sum(o_totalprice) tot_price from c.c_orders) v;
+---- RESULTS
+150000,99996
+---- TYPES
+bigint,bigint
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a50c3440/testdata/workloads/functional-query/queries/QueryTest/union.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-query/queries/QueryTest/union.test b/testdata/workloads/functional-query/queries/QueryTest/union.test
index 3ccecd9..ae75c12 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/union.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/union.test
@@ -16,6 +16,7 @@ int, boolean, tinyint, smallint, int, bigint, float, double, string, string, tim
 ====
 ---- QUERY
 # Only UNION ALL, no nested unions
+# IMPALA-3586: In this test, all union nodes are passed through.
 select id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month from alltypestiny where year=2009 and month=1
 union all
 select id, bool_col, tinyint_col, smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, string_col, timestamp_col, year, month from alltypestiny where year=2009 and month=1
@@ -1042,11 +1043,81 @@ DOUBLE
 # there are unmaterialized slots.
 set optimize_partition_key_scans=1;
 select t1.int_col
-from functional.alltypestiny t1 inner join
+from alltypestiny t1 inner join
   (select count(t2.tinyint_col) = 1337 as boolean_col,
-          min(t2.year) as int_col from functional.alltypestiny t2) t3
+          min(t2.year) as int_col from alltypestiny t2) t3
 on (t1.int_col = t3.int_col)
 ---- RESULTS
 ---- TYPES
 INT
-=====
\ No newline at end of file
+=====
+---- QUERY
+# IMPALA-3586: Verify that limit is obeyed in the passthrough case. This test
+# is relevant if the execution is on a single node (if exec_single_node_rows_threshold
+# large enough) because there is no exchange node above the union node to impose the
+# limit.
+select bigint_col from alltypestiny where bigint_col > 0
+union all
+(select bigint_col from alltypestiny where bigint_col > 0)
+limit 1
+---- RESULTS
+10
+---- TYPES
+bigint
+=====
+---- QUERY
+# IMPALA-3586: Input tuples that have non-nullable slots. Both operands should be passed
+# through by the union node.
+select count(*) from alltypestiny
+union all
+select count(*) from alltypestiny
+---- RESULTS
+8
+8
+---- TYPES
+bigint
+=====
+---- QUERY
+# IMPALA-3586: Both operands are not passed through.
+select bigint_col + 1 from alltypestiny
+union distinct
+select bigint_col + 1 from alltypestiny
+---- RESULTS
+1
+11
+---- TYPES
+bigint
+=====
+---- QUERY
+# IMPALA-3586: One operand is passed through, the other is not.
+select bigint_col + 1 from alltypestiny
+union distinct
+select bigint_col from alltypestiny
+---- RESULTS
+11
+10
+0
+1
+---- TYPES
+bigint
+=====
+---- QUERY
+# IMPALA-3678: The union operands that contain a join should not be passed through,
+# because the resulting row contains 2 tuples, instead of one. However, a semi join
+# outputs a row with only 1 tuple, so it should be passed through.
+select bigint_col from alltypestiny
+union
+select t1.bigint_col from alltypestiny t1 left semi join
+  alltypes t2 on t1.bigint_col = t2.bigint_col
+union
+select t1.bigint_col from alltypestiny t1 left join
+  alltypes t2 on t1.bigint_col = t2.bigint_col
+union
+select t1.bigint_col from alltypestiny t1 inner join
+  alltypes t2 on t1.bigint_col = t2.bigint_col
+---- RESULTS
+10
+0
+---- TYPES
+bigint
+=====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a50c3440/tests/query_test/test_queries.py
----------------------------------------------------------------------
diff --git a/tests/query_test/test_queries.py b/tests/query_test/test_queries.py
index d8e1f65..d875cda 100644
--- a/tests/query_test/test_queries.py
+++ b/tests/query_test/test_queries.py
@@ -75,6 +75,19 @@ class TestQueries(ImpalaTestSuite):
 
   def test_union(self, vector):
     self.run_test_case('QueryTest/union', vector)
+    # IMPALA-3586: The passthrough and materialized children are interleaved. The batch
+    # size is small to test the transition between materialized and passthrough children.
+    query_string = ("select count(c) from ( "
+        "select bigint_col + 1 as c from functional.alltypes limit 15 "
+        "union all "
+        "select bigint_col as c from functional.alltypes limit 15 "
+        "union all "
+        "select bigint_col + 1 as c from functional.alltypes limit 15 "
+        "union all "
+        "(select bigint_col as c from functional.alltypes limit 15)) t")
+    vector.get_value('exec_option')['batch_size'] = 10
+    result = self.execute_query(query_string, vector.get_value('exec_option'))
+    assert result.data[0] == '60'
 
   def test_sort(self, vector):
     if vector.get_value('table_format').file_format == 'hbase':