Fixed the union-all elimiation bug regarding non-attribute project expression.
diff --git a/cli/tests/command_executor/Analyze.test b/cli/tests/command_executor/Analyze.test
index ff20d9e..c391848 100644
--- a/cli/tests/command_executor/Analyze.test
+++ b/cli/tests/command_executor/Analyze.test
@@ -36,6 +36,7 @@
 +--------------------+
 ==
 
+# EliminateEmptyNode applies after having the exact stats.
 \analyze
 --
 Analyzing r ... done
@@ -43,6 +44,7 @@
 Analyzing t ... done
 ==
 
+# Aggregate on an empty table.
 SELECT COUNT(*) FROM r;
 --
 +--------------------+
@@ -52,6 +54,7 @@
 +--------------------+
 ==
 
+# Aggregate on an empty table.
 SELECT MIN(src) FROM r;
 --
 +-----------+
@@ -61,6 +64,7 @@
 +-----------+
 ==
 
+# InsertSelection on an empty table.
 INSERT INTO r SELECT * FROM s;
 SELECT r.src, r.dst FROM r;
 DELETE FROM r;
@@ -73,6 +77,12 @@
 +-----------+-----------+
 ==
 
+# Compute the exact stats for r after updates.
+\analyze r
+--
+Analyzing r ... done
+==
+
 # One side of InnerJoin is empty.
 SELECT r.src, r.dst
 FROM r, t
@@ -136,9 +146,9 @@
 ==
 
 # Union on two InnerJoins, one of which involves an empty relation.
-SELECT r.src, r.dst FROM r, s WHERE r.src=s.src AND r.dst=s.dst
+SELECT r.src, s.dst FROM r, s WHERE r.src=s.src AND r.dst=s.dst
 UNION
-SELECT s.src, s.dst FROM s, t WHERE s.src=t.src AND s.dst=t.dst;
+SELECT s.src, t.dst FROM s, t WHERE s.src=t.src AND s.dst=t.dst;
 --
 +-----------+-----------+
 |src        |dst        |
@@ -148,9 +158,9 @@
 ==
 
 # Union All on two InnerJoins, one of which involves an empty relation.
-SELECT r.src, r.dst FROM r, s WHERE r.src=s.src AND r.dst=s.dst
+SELECT r.src, s.dst FROM r, s WHERE r.src=s.src AND r.dst=s.dst
 UNION ALL
-SELECT s.src, s.dst FROM s, t WHERE s.src=t.src AND s.dst=t.dst;
+SELECT s.src, t.dst FROM s, t WHERE s.src=t.src AND s.dst=t.dst;
 --
 +-----------+-----------+
 |src        |dst        |
@@ -160,6 +170,20 @@
 +-----------+-----------+
 ==
 
+# Union All on two InnerJoins, one of which involves an empty relation.
+# One of the project expressions is a ScalarLiteral.
+SELECT s.src, r.dst FROM r, s WHERE r.src=s.src AND r.dst=s.dst
+UNION ALL
+SELECT 1 AS src, s.dst FROM s, t WHERE s.src=t.src AND s.dst=t.dst;
+--
++-----------+-----------+
+|src        |dst        |
++-----------+-----------+
+|          1|          0|
+|          1|          0|
++-----------+-----------+
+==
+
 DROP TABLE r;
 DROP TABLE s;
 DROP TABLE t;
diff --git a/query_optimizer/physical/Aggregate.cpp b/query_optimizer/physical/Aggregate.cpp
index 5ae9fc7..a8b86b6 100644
--- a/query_optimizer/physical/Aggregate.cpp
+++ b/query_optimizer/physical/Aggregate.cpp
@@ -27,7 +27,6 @@
 #include "query_optimizer/expressions/AttributeReference.hpp"
 #include "query_optimizer/expressions/ExpressionUtil.hpp"
 #include "query_optimizer/expressions/NamedExpression.hpp"
-#include "query_optimizer/expressions/PatternMatcher.hpp"
 #include "query_optimizer/expressions/Predicate.hpp"
 #include "query_optimizer/physical/PartitionSchemeHeader.hpp"
 #include "query_optimizer/physical/Physical.hpp"
@@ -93,22 +92,6 @@
   return referenced_attributes;
 }
 
-PhysicalPtr Aggregate::copyWithNewProjectExpressions(
-    const std::vector<E::NamedExpressionPtr> &output_expressions) const {
-  DCHECK_EQ(aggregate_expressions_.size(), output_expressions.size());
-
-  std::vector<E::AliasPtr> new_aggregate_expressions;
-  new_aggregate_expressions.reserve(aggregate_expressions_.size());
-  for (const auto &output_expression : output_expressions) {
-    DCHECK(E::SomeAlias::Matches(output_expression));
-
-    new_aggregate_expressions.push_back(
-        std::static_pointer_cast<const E::Alias>(output_expression));
-  }
-
-  return Create(input_, grouping_expressions_, new_aggregate_expressions, filter_predicate_);
-}
-
 void Aggregate::getFieldStringItems(
     std::vector<std::string> *inline_field_names,
     std::vector<std::string> *inline_field_values,
diff --git a/query_optimizer/physical/Aggregate.hpp b/query_optimizer/physical/Aggregate.hpp
index 736082c..68f8811 100644
--- a/query_optimizer/physical/Aggregate.hpp
+++ b/query_optimizer/physical/Aggregate.hpp
@@ -103,9 +103,6 @@
                   has_repartition, partition_scheme_header);
   }
 
-  PhysicalPtr copyWithNewProjectExpressions(
-      const std::vector<expressions::NamedExpressionPtr> &output_expressions) const override;
-
   bool maybeCopyWithPrunedExpressions(
       const expressions::UnorderedNamedExpressionSet &referenced_expressions,
       PhysicalPtr *output) const override {
diff --git a/query_optimizer/physical/CMakeLists.txt b/query_optimizer/physical/CMakeLists.txt
index 9f866b8..437488a 100644
--- a/query_optimizer/physical/CMakeLists.txt
+++ b/query_optimizer/physical/CMakeLists.txt
@@ -59,7 +59,6 @@
                       quickstep_queryoptimizer_expressions_AttributeReference
                       quickstep_queryoptimizer_expressions_ExpressionUtil
                       quickstep_queryoptimizer_expressions_NamedExpression
-                      quickstep_queryoptimizer_expressions_PatternMatcher
                       quickstep_queryoptimizer_expressions_Predicate
                       quickstep_queryoptimizer_physical_PartitionSchemeHeader
                       quickstep_queryoptimizer_physical_Physical
diff --git a/query_optimizer/rules/EliminateEmptyNode.cpp b/query_optimizer/rules/EliminateEmptyNode.cpp
index fd1c383..f619e67 100644
--- a/query_optimizer/rules/EliminateEmptyNode.cpp
+++ b/query_optimizer/rules/EliminateEmptyNode.cpp
@@ -153,42 +153,37 @@
 
 P::PhysicalPtr CopyWithNewProjectExpressions(const P::UnionAllPtr &union_all,
                                              const P::PhysicalPtr &child) {
-  const auto &project_attributes = union_all->project_attributes();
+  const std::vector<E::NamedExpressionPtr> *project_expressions = nullptr;
+
+  switch (child->getPhysicalType()) {
+    case P::PhysicalType::kHashJoin:
+    case P::PhysicalType::kNestedLoopsJoin: {
+      const auto &join = std::static_pointer_cast<const P::Join>(child);
+      project_expressions = &(join->project_expressions());
+      break;
+    }
+    case P::PhysicalType::kSelection: {
+      const auto &selection = std::static_pointer_cast<const P::Selection>(child);
+      project_expressions = &(selection->project_expressions());
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected PhysicalType.";
+  }
+  DCHECK(project_expressions);
 
   std::vector<E::NamedExpressionPtr> alias_expressions;
-  P::AggregatePtr aggregate;
-  if (P::SomeAggregate::MatchesWithConditionalCast(child, &aggregate)) {
-    const auto &aggregate_expressions = aggregate->aggregate_expressions();
-    alias_expressions.reserve(aggregate_expressions.size());
+  alias_expressions.reserve(project_expressions->size());
 
-    int aid = 0;
-    for (const auto &project_attribute : project_attributes) {
-      const auto alias_referenced_attributes =
-          aggregate_expressions[aid]->getReferencedAttributes();
-      DCHECK_EQ(1u, alias_referenced_attributes.size());
-
-      alias_expressions.emplace_back(E::Alias::Create(
-          project_attribute->id(),
-          alias_referenced_attributes.front(),
-          project_attribute->attribute_name(),
-          project_attribute->attribute_alias(),
-          project_attribute->relation_name()));
-      ++aid;
-    }
-  } else {
-    const auto child_output_attributes = child->getOutputAttributes();
-    alias_expressions.reserve(child_output_attributes.size());
-
-    int aid = 0;
-    for (const auto &project_attribute : project_attributes) {
-      alias_expressions.emplace_back(E::Alias::Create(
-          project_attribute->id(),
-          child_output_attributes[aid],
-          project_attribute->attribute_name(),
-          project_attribute->attribute_alias(),
-          project_attribute->relation_name()));
-      ++aid;
-    }
+  int aid = 0;
+  for (const auto &project_attribute : union_all->project_attributes()) {
+    alias_expressions.emplace_back(E::Alias::Create(
+        project_attribute->id(),
+        (*project_expressions)[aid],
+        project_attribute->attribute_name(),
+        project_attribute->attribute_alias(),
+        project_attribute->relation_name()));
+    ++aid;
   }
 
   return child->copyWithNewProjectExpressions(alias_expressions);