You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by ji...@apache.org on 2018/05/09 23:10:59 UTC

[2/2] incubator-quickstep git commit: QUICKSTEP-121: Added the self-join support.

QUICKSTEP-121: Added the self-join support.


Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/8b7c3801
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/8b7c3801
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/8b7c3801

Branch: refs/heads/master
Commit: 8b7c38010e1505ef03e0b6de8c6ac16cceb04695
Parents: 42588d4
Author: Zuyu Zhang <zu...@cs.wisc.edu>
Authored: Tue May 1 00:48:34 2018 -0500
Committer: Zuyu Zhang <zu...@cs.wisc.edu>
Committed: Wed May 9 16:34:47 2018 -0500

----------------------------------------------------------------------
 expressions/ExpressionFactories.cpp             | 17 +++-
 expressions/Expressions.proto                   |  7 ++
 expressions/predicate/ComparisonPredicate.cpp   | 26 +++---
 expressions/predicate/ComparisonPredicate.hpp   |  2 -
 expressions/predicate/ConjunctionPredicate.cpp  |  4 -
 expressions/predicate/ConjunctionPredicate.hpp  |  2 -
 expressions/predicate/DisjunctionPredicate.cpp  |  4 -
 expressions/predicate/DisjunctionPredicate.hpp  |  2 -
 expressions/predicate/NegationPredicate.cpp     |  4 -
 expressions/predicate/NegationPredicate.hpp     |  2 -
 expressions/predicate/Predicate.hpp             |  6 --
 expressions/predicate/TrivialPredicates.hpp     |  4 -
 expressions/scalar/Scalar.hpp                   | 50 +++++------
 expressions/scalar/ScalarAttribute.cpp          | 58 +++++++++----
 expressions/scalar/ScalarAttribute.hpp          | 10 +--
 expressions/scalar/ScalarBinaryExpression.cpp   | 80 +++++------------
 expressions/scalar/ScalarBinaryExpression.hpp   |  4 -
 expressions/scalar/ScalarCaseExpression.cpp     | 62 +++-----------
 expressions/scalar/ScalarCaseExpression.hpp     |  4 -
 expressions/scalar/ScalarLiteral.cpp            |  2 -
 expressions/scalar/ScalarLiteral.hpp            |  4 -
 expressions/scalar/ScalarSharedExpression.cpp   | 14 +--
 expressions/scalar/ScalarSharedExpression.hpp   |  4 -
 expressions/scalar/ScalarUnaryExpression.cpp    | 18 +---
 expressions/scalar/ScalarUnaryExpression.hpp    |  4 -
 .../tests/ScalarCaseExpression_unittest.cpp     | 58 ++++++-------
 query_optimizer/ExecutionGenerator.cpp          | 88 ++++++++++++-------
 query_optimizer/ExecutionGenerator.hpp          | 21 +++--
 query_optimizer/expressions/Alias.cpp           |  5 +-
 query_optimizer/expressions/Alias.hpp           |  5 +-
 .../expressions/AttributeReference.cpp          | 19 ++++-
 .../expressions/AttributeReference.hpp          |  5 +-
 .../expressions/BinaryExpression.cpp            |  9 +-
 .../expressions/BinaryExpression.hpp            |  5 +-
 query_optimizer/expressions/CMakeLists.txt      |  1 +
 query_optimizer/expressions/Cast.cpp            | 10 ++-
 query_optimizer/expressions/Cast.hpp            |  5 +-
 .../expressions/CommonSubexpression.cpp         |  7 +-
 .../expressions/CommonSubexpression.hpp         |  5 +-
 .../expressions/ComparisonExpression.cpp        |  9 +-
 .../expressions/ComparisonExpression.hpp        |  5 +-
 query_optimizer/expressions/Exists.cpp          |  5 +-
 query_optimizer/expressions/Exists.hpp          |  5 +-
 query_optimizer/expressions/InTableQuery.cpp    |  5 +-
 query_optimizer/expressions/InTableQuery.hpp    |  5 +-
 query_optimizer/expressions/InValueList.cpp     |  7 +-
 query_optimizer/expressions/InValueList.hpp     |  5 +-
 query_optimizer/expressions/LogicalAnd.cpp      |  9 +-
 query_optimizer/expressions/LogicalAnd.hpp      |  5 +-
 query_optimizer/expressions/LogicalNot.cpp      |  7 +-
 query_optimizer/expressions/LogicalNot.hpp      |  5 +-
 query_optimizer/expressions/LogicalOr.cpp       |  9 +-
 query_optimizer/expressions/LogicalOr.hpp       |  5 +-
 query_optimizer/expressions/Predicate.hpp       |  7 +-
 .../expressions/PredicateLiteral.cpp            |  5 +-
 .../expressions/PredicateLiteral.hpp            |  5 +-
 query_optimizer/expressions/Scalar.hpp          |  8 +-
 query_optimizer/expressions/ScalarLiteral.cpp   |  5 +-
 query_optimizer/expressions/ScalarLiteral.hpp   |  5 +-
 query_optimizer/expressions/SearchedCase.cpp    | 17 ++--
 query_optimizer/expressions/SearchedCase.hpp    |  5 +-
 query_optimizer/expressions/SimpleCase.cpp      |  7 +-
 query_optimizer/expressions/SimpleCase.hpp      |  5 +-
 .../expressions/SubqueryExpression.cpp          |  5 +-
 .../expressions/SubqueryExpression.hpp          |  5 +-
 query_optimizer/expressions/UnaryExpression.cpp |  7 +-
 query_optimizer/expressions/UnaryExpression.hpp |  5 +-
 .../tests/execution_generator/Select.test       | 56 +++++++++++-
 relational_operators/HashJoinOperator.cpp       | 90 +++++++-------------
 .../NestedLoopsJoinOperator.cpp                 |  9 +-
 .../tests/HashJoinOperator_unittest.cpp         | 34 ++++----
 71 files changed, 536 insertions(+), 467 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/ExpressionFactories.cpp
----------------------------------------------------------------------
diff --git a/expressions/ExpressionFactories.cpp b/expressions/ExpressionFactories.cpp
index 871db50..cab99fd 100644
--- a/expressions/ExpressionFactories.cpp
+++ b/expressions/ExpressionFactories.cpp
@@ -52,6 +52,8 @@
 
 namespace quickstep {
 
+namespace S = serialization;
+
 class Type;
 
 Predicate* PredicateFactory::ReconstructFromProto(const serialization::Predicate &proto,
@@ -163,9 +165,22 @@ Scalar* ScalarFactory::ReconstructFromProto(const serialization::Scalar &proto,
     case serialization::Scalar::ATTRIBUTE: {
       const relation_id rel_id = proto.GetExtension(serialization::ScalarAttribute::relation_id);
 
+      Scalar::JoinSide join_side;
+      switch (proto.GetExtension(S::ScalarAttribute::join_side)) {
+        case S::ScalarAttribute::NONE:
+          join_side = Scalar::kNone;
+          break;
+        case S::ScalarAttribute::LEFT_SIDE:
+          join_side = Scalar::kLeftSide;
+          break;
+        case S::ScalarAttribute::RIGHT_SIDE:
+          join_side = Scalar::kRightSide;
+          break;
+      }
+
       DCHECK(database.hasRelationWithId(rel_id));
       return new ScalarAttribute(*database.getRelationSchemaById(rel_id).getAttributeById(
-          proto.GetExtension(serialization::ScalarAttribute::attribute_id)));
+          proto.GetExtension(serialization::ScalarAttribute::attribute_id)), join_side);
     }
     case serialization::Scalar::UNARY_EXPRESSION: {
       return new ScalarUnaryExpression(

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/Expressions.proto
----------------------------------------------------------------------
diff --git a/expressions/Expressions.proto b/expressions/Expressions.proto
index 8b4611e..aabb707 100644
--- a/expressions/Expressions.proto
+++ b/expressions/Expressions.proto
@@ -95,9 +95,16 @@ message ScalarLiteral {
 }
 
 message ScalarAttribute {
+  enum JoinSide {
+    NONE = 0;
+    LEFT_SIDE = 1;
+    RIGHT_SIDE = 2;
+  }
+
   extend Scalar {
     optional int32 relation_id = 64;
     optional int32 attribute_id = 65;
+    optional JoinSide join_side = 66;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/ComparisonPredicate.cpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/ComparisonPredicate.cpp b/expressions/predicate/ComparisonPredicate.cpp
index 2f7b84b..0417170 100644
--- a/expressions/predicate/ComparisonPredicate.cpp
+++ b/expressions/predicate/ComparisonPredicate.cpp
@@ -94,28 +94,22 @@ bool ComparisonPredicate::matchesForSingleTuple(const ValueAccessor &accessor,
 
 bool ComparisonPredicate::matchesForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (fast_comparator_.get() == nullptr) {
     return static_result_;
-  } else {
-    return fast_comparator_->compareTypedValues(
-        left_operand_->getValueForJoinedTuples(left_accessor,
-                                               left_relation_id,
-                                               left_tuple_id,
-                                               right_accessor,
-                                               right_relation_id,
-                                               right_tuple_id),
-        right_operand_->getValueForJoinedTuples(left_accessor,
-                                                left_relation_id,
-                                                left_tuple_id,
-                                                right_accessor,
-                                                right_relation_id,
-                                                right_tuple_id));
   }
+
+  return fast_comparator_->compareTypedValues(
+      left_operand_->getValueForJoinedTuples(left_accessor,
+                                             left_tuple_id,
+                                             right_accessor,
+                                             right_tuple_id),
+      right_operand_->getValueForJoinedTuples(left_accessor,
+                                              left_tuple_id,
+                                              right_accessor,
+                                              right_tuple_id));
 }
 
 TupleIdSequence* ComparisonPredicate::getAllMatches(

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/ComparisonPredicate.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/ComparisonPredicate.hpp b/expressions/predicate/ComparisonPredicate.hpp
index 1ef2cb1..014e378 100644
--- a/expressions/predicate/ComparisonPredicate.hpp
+++ b/expressions/predicate/ComparisonPredicate.hpp
@@ -83,10 +83,8 @@ class ComparisonPredicate : public Predicate {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   TupleIdSequence* getAllMatches(ValueAccessor *accessor,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/ConjunctionPredicate.cpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/ConjunctionPredicate.cpp b/expressions/predicate/ConjunctionPredicate.cpp
index 4f5cc77..39d9e58 100644
--- a/expressions/predicate/ConjunctionPredicate.cpp
+++ b/expressions/predicate/ConjunctionPredicate.cpp
@@ -85,10 +85,8 @@ bool ConjunctionPredicate::matchesForSingleTuple(const ValueAccessor &accessor,
 
 bool ConjunctionPredicate::matchesForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (has_static_result_) {
     return static_result_;
@@ -97,10 +95,8 @@ bool ConjunctionPredicate::matchesForJoinedTuples(
          it != dynamic_operand_list_.end();
          ++it) {
       if (!it->matchesForJoinedTuples(left_accessor,
-                                      left_relation_id,
                                       left_tuple_id,
                                       right_accessor,
-                                      right_relation_id,
                                       right_tuple_id)) {
         return false;
       }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/ConjunctionPredicate.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/ConjunctionPredicate.hpp b/expressions/predicate/ConjunctionPredicate.hpp
index b24036a..07148a7 100644
--- a/expressions/predicate/ConjunctionPredicate.hpp
+++ b/expressions/predicate/ConjunctionPredicate.hpp
@@ -63,10 +63,8 @@ class ConjunctionPredicate : public PredicateWithList {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   TupleIdSequence* getAllMatches(ValueAccessor *accessor,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/DisjunctionPredicate.cpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/DisjunctionPredicate.cpp b/expressions/predicate/DisjunctionPredicate.cpp
index e117c99..4ac3bd7 100644
--- a/expressions/predicate/DisjunctionPredicate.cpp
+++ b/expressions/predicate/DisjunctionPredicate.cpp
@@ -85,10 +85,8 @@ bool DisjunctionPredicate::matchesForSingleTuple(const ValueAccessor &accessor,
 
 bool DisjunctionPredicate::matchesForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (has_static_result_) {
     return static_result_;
@@ -97,10 +95,8 @@ bool DisjunctionPredicate::matchesForJoinedTuples(
          it != dynamic_operand_list_.end();
          ++it) {
       if (it->matchesForJoinedTuples(left_accessor,
-                                     left_relation_id,
                                      left_tuple_id,
                                      right_accessor,
-                                     right_relation_id,
                                      right_tuple_id)) {
         return true;
       }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/DisjunctionPredicate.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/DisjunctionPredicate.hpp b/expressions/predicate/DisjunctionPredicate.hpp
index 2127573..2b237e6 100644
--- a/expressions/predicate/DisjunctionPredicate.hpp
+++ b/expressions/predicate/DisjunctionPredicate.hpp
@@ -63,10 +63,8 @@ class DisjunctionPredicate : public PredicateWithList {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   TupleIdSequence* getAllMatches(ValueAccessor *accessor,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/NegationPredicate.cpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/NegationPredicate.cpp b/expressions/predicate/NegationPredicate.cpp
index 92a8411..ad3238a 100644
--- a/expressions/predicate/NegationPredicate.cpp
+++ b/expressions/predicate/NegationPredicate.cpp
@@ -54,19 +54,15 @@ bool NegationPredicate::matchesForSingleTuple(const ValueAccessor &accessor,
 
 bool NegationPredicate::matchesForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (has_static_result_) {
     return static_result_;
   } else {
     return !(operand_->matchesForJoinedTuples(left_accessor,
-                                              left_relation_id,
                                               left_tuple_id,
                                               right_accessor,
-                                              right_relation_id,
                                               right_tuple_id));
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/NegationPredicate.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/NegationPredicate.hpp b/expressions/predicate/NegationPredicate.hpp
index ec005ea..7afcf1c 100644
--- a/expressions/predicate/NegationPredicate.hpp
+++ b/expressions/predicate/NegationPredicate.hpp
@@ -91,10 +91,8 @@ class NegationPredicate : public Predicate {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   TupleIdSequence* getAllMatches(ValueAccessor *accessor,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/Predicate.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/Predicate.hpp b/expressions/predicate/Predicate.hpp
index df04644..31fbb9a 100644
--- a/expressions/predicate/Predicate.hpp
+++ b/expressions/predicate/Predicate.hpp
@@ -123,15 +123,11 @@ class Predicate : public Expression {
    * @param left_accessor The ValueAccessor that the first of the joined tuples
    *        will be read from (this does NOT necessarily correspond to the left
    *        operand of a binary operation).
-   * @param left_relation_id The ID of the relation that left_accessor provides
-   *        access to.
    * @param left_tuple_id The ID of the tuple (the absolute position) from
    *        left_accessor to evaluate this Predicate for.
    * @param right_accessor The ValueAccessor that the second of the joined
    *        tuples will be read from (this does NOT necessarily correspond to
    *        the right operand of a binary operation).
-   * @param right_relation_id The ID of the relation that right_accessor
-   *        provides access to.
    * @param right_tuple_id The ID of the tuple (the absolute position) from
    *        right_accessor to evaluate this Predicate for.
    * @return Whether this predicate is true for the given tuples.
@@ -144,10 +140,8 @@ class Predicate : public Expression {
   // a smallish set of matches from a hash-join by a residual predicate).
   virtual bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const = 0;
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/predicate/TrivialPredicates.hpp
----------------------------------------------------------------------
diff --git a/expressions/predicate/TrivialPredicates.hpp b/expressions/predicate/TrivialPredicates.hpp
index 4e44976..e313cd5 100644
--- a/expressions/predicate/TrivialPredicates.hpp
+++ b/expressions/predicate/TrivialPredicates.hpp
@@ -84,10 +84,8 @@ class TruePredicate : public TrivialPredicate {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override {
     return true;
   }
@@ -137,10 +135,8 @@ class FalsePredicate : public TrivialPredicate {
 
   bool matchesForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override {
     return false;
   }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/Scalar.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/Scalar.hpp b/expressions/scalar/Scalar.hpp
index 6e482c2..0c1cba1 100644
--- a/expressions/scalar/Scalar.hpp
+++ b/expressions/scalar/Scalar.hpp
@@ -51,6 +51,15 @@ struct SubBlocksReference;
 class Scalar : public Expression {
  public:
   /**
+   * @brief The possible binary join side of Scalar values.
+   **/
+  enum JoinSide {
+    kNone = 0,
+    kLeftSide,
+    kRightSide
+  };
+
+  /**
    * @brief The possible provenance of Scalar values.
    **/
   enum ScalarDataSource {
@@ -128,28 +137,35 @@ class Scalar : public Expression {
    * @param left_accessor The ValueAccessor that the first of the joined
    *        tuples can be read from (this does NOT necessarily correspond to
    *        the left operand of a binary operation).
-   * @param left_relation_id The ID of the relation that left_tuple_store
-   *        belongs to.
    * @param left_tuple_id The ID of the tuple in left_tuple_store to evaluate
    *        this Scalar for.
    * @param right_accessor The ValueAccessor that the second of the joined
    *        tuples can be read from (this does NOT necessarily correspond to
    *        the right operand of a binary operation).
-   * @param right_relation_id The ID of the relation that right_tuple_store
-   *        belongs to.
    * @param right_tuple_id The ID of the tuple in right_tuple_store to evaluate
    *        this Scalar for.
    * @return The value of this scalar for the given tuples.
    **/
   virtual TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const = 0;
 
   /**
+   * @brief If it is possible to get this Scalar's values directly from a
+   *        ValueAccessor, return the binary join side of the ValueAccessor
+   *        should belong to.
+   *
+   * @return The binary join side for ValueAccessors that can directly produce
+   *         this Scalar's values, or kNone if values can not be obtained
+   *         directly from a ValueAccessor.
+   **/
+  JoinSide join_side() const {
+    return join_side_;
+  }
+
+  /**
    * @brief Determine whether this Scalar's value is static (i.e. whether it is
    *        the same regardless of tuple).
    *
@@ -181,19 +197,6 @@ class Scalar : public Expression {
   }
 
   /**
-   * @brief If it is possible to get this Scalar's values directly from a
-   *        ValueAccessor, return the ID of the relation that such a
-   *        ValueAccessor should belong to.
-   *
-   * @return The relation_id for ValueAccessors that can directly produce this
-   *         Scalar's values, or -1 if values can not be obtained directly from
-   *         a ValueAccessor.
-   **/
-  virtual relation_id getRelationIdForValueAccessor() const {
-    return -1;
-  }
-
-  /**
    * @brief Get this Scalar's values for all tuples accesible via a
    *        ValueAccessor.
    *
@@ -217,10 +220,8 @@ class Scalar : public Expression {
    * @brief Get this Scalar's value for all specified joined tuples from two
    *        ValueAccessors.
    *
-   * @param left_relation_id The ID of the left relation in the join.
    * @param left_accessor A ValueAccessor which will be used to access tuples
    *        from the left relation.
-   * @param right_relation_id The ID of the right relation in the join.
    * @param right_accessor A ValueAccessor which will be used to access tuples
    *        from the right relation.
    * @param joined_tuple_ids A series of pairs of tuple ids from the left and
@@ -231,9 +232,7 @@ class Scalar : public Expression {
    *         specified by joined_tuple_ids.
    **/
   virtual ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const = 0;
@@ -247,10 +246,11 @@ class Scalar : public Expression {
       std::vector<std::string> *container_child_field_names,
       std::vector<std::vector<const Expression*>> *container_child_fields) const override;
 
-  explicit Scalar(const Type &type)
-      : Expression(), type_(type) {}
+  explicit Scalar(const Type &type, const JoinSide join_side = kNone)
+      : Expression(), type_(type), join_side_(join_side) {}
 
   const Type &type_;
+  const JoinSide join_side_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Scalar);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarAttribute.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarAttribute.cpp b/expressions/scalar/ScalarAttribute.cpp
index 944dc35..8a75bb0 100644
--- a/expressions/scalar/ScalarAttribute.cpp
+++ b/expressions/scalar/ScalarAttribute.cpp
@@ -28,6 +28,7 @@
 #include "catalog/CatalogRelationSchema.hpp"
 #include "catalog/CatalogTypedefs.hpp"
 #include "expressions/Expressions.pb.h"
+#include "expressions/scalar/Scalar.hpp"
 #include "storage/StorageBlockInfo.hpp"
 #include "storage/ValueAccessor.hpp"
 #include "storage/ValueAccessorUtil.hpp"
@@ -40,8 +41,11 @@
 
 namespace quickstep {
 
-ScalarAttribute::ScalarAttribute(const CatalogAttribute &attribute)
-    : Scalar(attribute.getType()),
+namespace S = serialization;
+
+ScalarAttribute::ScalarAttribute(const CatalogAttribute &attribute,
+                                 const JoinSide join_side)
+    : Scalar(attribute.getType(), join_side),
       attribute_(attribute) {
 }
 
@@ -51,11 +55,25 @@ serialization::Scalar ScalarAttribute::getProto() const {
   proto.SetExtension(serialization::ScalarAttribute::relation_id, attribute_.getParent().getID());
   proto.SetExtension(serialization::ScalarAttribute::attribute_id, attribute_.getID());
 
+  S::ScalarAttribute::JoinSide join_side_proto;
+  switch (join_side_) {
+    case kNone:
+      join_side_proto = S::ScalarAttribute::NONE;
+      break;
+    case kLeftSide:
+      join_side_proto = S::ScalarAttribute::LEFT_SIDE;
+      break;
+    case kRightSide:
+      join_side_proto = S::ScalarAttribute::RIGHT_SIDE;
+      break;
+  }
+  proto.SetExtension(S::ScalarAttribute::join_side, join_side_proto);
+
   return proto;
 }
 
 Scalar* ScalarAttribute::clone() const {
-  return new ScalarAttribute(attribute_);
+  return new ScalarAttribute(attribute_, join_side_);
 }
 
 TypedValue ScalarAttribute::getValueForSingleTuple(const ValueAccessor &accessor,
@@ -65,18 +83,16 @@ TypedValue ScalarAttribute::getValueForSingleTuple(const ValueAccessor &accessor
 
 TypedValue ScalarAttribute::getValueForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
-  // FIXME(chasseur): This can get confused and break for self-joins.
-  DCHECK((attribute_.getParent().getID() == left_relation_id)
-         || (attribute_.getParent().getID() == right_relation_id));
-  if (attribute_.getParent().getID() == left_relation_id) {
+  DCHECK(join_side_ != kNone);
+
+  if (join_side_ == kLeftSide) {
     return left_accessor.getTypedValueAtAbsolutePositionVirtual(attribute_.getID(),
                                                                 left_tuple_id);
   } else {
+    DCHECK(join_side_ == kRightSide);
     return right_accessor.getTypedValueAtAbsolutePositionVirtual(attribute_.getID(),
                                                                  right_tuple_id);
   }
@@ -86,10 +102,6 @@ attribute_id ScalarAttribute::getAttributeIdForValueAccessor() const {
   return attribute_.getID();
 }
 
-relation_id ScalarAttribute::getRelationIdForValueAccessor() const {
-  return attribute_.getParent().getID();
-}
-
 ColumnVectorPtr ScalarAttribute::getAllValues(
     ValueAccessor *accessor,
     const SubBlocksReference *sub_blocks_ref,
@@ -157,19 +169,16 @@ ColumnVectorPtr ScalarAttribute::getAllValues(
 }
 
 ColumnVectorPtr ScalarAttribute::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {
-  DCHECK((attribute_.getParent().getID() == left_relation_id)
-         || (attribute_.getParent().getID() == right_relation_id));
+  DCHECK(join_side_ != kNone);
 
   const attribute_id attr_id = attribute_.getID();
   const Type &result_type = attribute_.getType();
 
-  const bool using_left_relation = (attribute_.getParent().getID() == left_relation_id);
+  const bool using_left_relation = (join_side_ == kLeftSide);
   ValueAccessor *accessor = using_left_relation ? left_accessor
                                                 : right_accessor;
 
@@ -232,6 +241,19 @@ void ScalarAttribute::getFieldStringItems(
 
   inline_field_names->emplace_back("attribute");
   inline_field_values->emplace_back(std::to_string(attribute_.getID()));
+
+  switch (join_side_) {
+    case kNone:
+      break;
+    case kLeftSide:
+      inline_field_names->emplace_back("join_side");
+      inline_field_values->push_back("left_side");
+      break;
+    case kRightSide:
+      inline_field_names->emplace_back("join_side");
+      inline_field_values->push_back("right_side");
+      break;
+  }
 }
 
 }  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarAttribute.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarAttribute.hpp b/expressions/scalar/ScalarAttribute.hpp
index 4d30fe9..cd718c8 100644
--- a/expressions/scalar/ScalarAttribute.hpp
+++ b/expressions/scalar/ScalarAttribute.hpp
@@ -53,8 +53,10 @@ class ScalarAttribute : public Scalar {
    * @brief Constructor.
    *
    * @param attribute The attribute to use.
+   * @param join_side The join side of which this attribute belongs to.
    **/
-  explicit ScalarAttribute(const CatalogAttribute &attribute);
+  explicit ScalarAttribute(const CatalogAttribute &attribute,
+                           const JoinSide join_side = kNone);
 
   serialization::Scalar getProto() const override;
 
@@ -69,24 +71,18 @@ class ScalarAttribute : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   attribute_id getAttributeIdForValueAccessor() const override;
 
-  relation_id getRelationIdForValueAccessor() const override;
-
   ColumnVectorPtr getAllValues(ValueAccessor *accessor,
                                const SubBlocksReference *sub_blocks_ref,
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarBinaryExpression.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarBinaryExpression.cpp b/expressions/scalar/ScalarBinaryExpression.cpp
index b3568f8..ecbe84f 100644
--- a/expressions/scalar/ScalarBinaryExpression.cpp
+++ b/expressions/scalar/ScalarBinaryExpression.cpp
@@ -79,26 +79,20 @@ TypedValue ScalarBinaryExpression::getValueForSingleTuple(const ValueAccessor &a
 
 TypedValue ScalarBinaryExpression::getValueForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (fast_operator_.get() == nullptr) {
     return static_value_.makeReferenceToThis();
   } else {
     return fast_operator_->applyToTypedValues(
         left_operand_->getValueForJoinedTuples(left_accessor,
-                                               left_relation_id,
                                                left_tuple_id,
                                                right_accessor,
-                                               right_relation_id,
                                                right_tuple_id),
         right_operand_->getValueForJoinedTuples(left_accessor,
-                                                left_relation_id,
                                                 left_tuple_id,
                                                 right_accessor,
-                                                right_relation_id,
                                                 right_tuple_id));
   }
 }
@@ -199,9 +193,7 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValues(
 }
 
 ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {
@@ -216,12 +208,9 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
       const attribute_id right_operand_attr_id
           = right_operand_->getAttributeIdForValueAccessor();
       if (right_operand_attr_id != -1) {
-        const relation_id right_operand_relation_id
-            = right_operand_->getRelationIdForValueAccessor();
-        DCHECK_NE(right_operand_relation_id, -1);
-        DCHECK((right_operand_relation_id == left_relation_id)
-               || (right_operand_relation_id == right_relation_id));
-        const bool using_left_relation = (right_operand_relation_id == left_relation_id);
+        const JoinSide join_side = right_operand_->join_side();
+        DCHECK(join_side != kNone);
+        const bool using_left_relation = (join_side == kLeftSide);
         ValueAccessor *right_operand_accessor = using_left_relation ? left_accessor
                                                                     : right_accessor;
         return ColumnVectorPtr(
@@ -235,9 +224,7 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
       ColumnVectorPtr right_result(
-          right_operand_->getAllValuesForJoin(left_relation_id,
-                                              left_accessor,
-                                              right_relation_id,
+          right_operand_->getAllValuesForJoin(left_accessor,
                                               right_accessor,
                                               joined_tuple_ids,
                                               cv_cache));
@@ -250,12 +237,9 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
       const attribute_id left_operand_attr_id
           = left_operand_->getAttributeIdForValueAccessor();
       if (left_operand_attr_id != -1) {
-        const relation_id left_operand_relation_id
-            = left_operand_->getRelationIdForValueAccessor();
-        DCHECK_NE(left_operand_relation_id, -1);
-        DCHECK((left_operand_relation_id == left_relation_id)
-               || (left_operand_relation_id == right_relation_id));
-        const bool using_left_relation = (left_operand_relation_id == left_relation_id);
+        const JoinSide join_side = left_operand_->join_side();
+        DCHECK(join_side != kNone);
+        const bool using_left_relation = (join_side == kLeftSide);
         ValueAccessor *left_operand_accessor = using_left_relation ? left_accessor
                                                                    : right_accessor;
         return ColumnVectorPtr(
@@ -269,9 +253,7 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
       ColumnVectorPtr left_result(
-          left_operand_->getAllValuesForJoin(left_relation_id,
-                                             left_accessor,
-                                             right_relation_id,
+          left_operand_->getAllValuesForJoin(left_accessor,
                                              right_accessor,
                                              joined_tuple_ids,
                                              cv_cache));
@@ -286,25 +268,17 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
       const attribute_id right_operand_attr_id
           = right_operand_->getAttributeIdForValueAccessor();
       if (left_operand_attr_id != -1) {
-        const relation_id left_operand_relation_id
-            = left_operand_->getRelationIdForValueAccessor();
-        DCHECK_NE(left_operand_relation_id, -1);
-        DCHECK((left_operand_relation_id == left_relation_id)
-               || (left_operand_relation_id == right_relation_id));
-        const bool using_left_relation_for_left_operand
-            = (left_operand_relation_id == left_relation_id);
+        const JoinSide join_side = left_operand_->join_side();
+        DCHECK(join_side != kNone);
+        const bool using_left_relation_for_left_operand = (join_side == kLeftSide);
         ValueAccessor *left_operand_accessor = using_left_relation_for_left_operand ? left_accessor
                                                                                     : right_accessor;
 
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN_WITH_BINARY_EXPRESSIONS
         if (right_operand_attr_id != -1) {
-          const relation_id right_operand_relation_id
-              = right_operand_->getRelationIdForValueAccessor();
-          DCHECK_NE(right_operand_relation_id, -1);
-          DCHECK((right_operand_relation_id == left_relation_id)
-                 || (right_operand_relation_id == right_relation_id));
-          const bool using_left_relation_for_right_operand
-              = (right_operand_relation_id == left_relation_id);
+          const JoinSide join_side = right_operand_->join_side();
+          DCHECK(join_side != kNone);
+          const bool using_left_relation_for_right_operand = (join_side == kLeftSide);
           ValueAccessor *right_operand_accessor = using_left_relation_for_right_operand ? left_accessor
                                                                                         : right_accessor;
           return ColumnVectorPtr(
@@ -318,9 +292,7 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
         }
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN_WITH_BINARY_EXPRESSIONS
         ColumnVectorPtr right_result(
-            right_operand_->getAllValuesForJoin(left_relation_id,
-                                                left_accessor,
-                                                right_relation_id,
+            right_operand_->getAllValuesForJoin(left_accessor,
                                                 right_accessor,
                                                 joined_tuple_ids,
                                                 cv_cache));
@@ -333,20 +305,14 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
                 *right_result,
                 joined_tuple_ids));
       } else if (right_operand_attr_id != -1) {
-        const relation_id right_operand_relation_id
-            = right_operand_->getRelationIdForValueAccessor();
-        DCHECK_NE(right_operand_relation_id, -1);
-        DCHECK((right_operand_relation_id == left_relation_id)
-               || (right_operand_relation_id == right_relation_id));
-        const bool using_left_relation_for_right_operand
-            = (right_operand_relation_id == left_relation_id);
+        const JoinSide join_side = right_operand_->join_side();
+        DCHECK(join_side != kNone);
+        const bool using_left_relation_for_right_operand = (join_side == kLeftSide);
         ValueAccessor *right_operand_accessor = using_left_relation_for_right_operand ? left_accessor
                                                                                       : right_accessor;
 
         ColumnVectorPtr left_result(
-            left_operand_->getAllValuesForJoin(left_relation_id,
-                                               left_accessor,
-                                               right_relation_id,
+            left_operand_->getAllValuesForJoin(left_accessor,
                                                right_accessor,
                                                joined_tuple_ids,
                                                cv_cache));
@@ -361,16 +327,12 @@ ColumnVectorPtr ScalarBinaryExpression::getAllValuesForJoin(
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
       ColumnVectorPtr left_result(
-          left_operand_->getAllValuesForJoin(left_relation_id,
-                                             left_accessor,
-                                             right_relation_id,
+          left_operand_->getAllValuesForJoin(left_accessor,
                                              right_accessor,
                                              joined_tuple_ids,
                                              cv_cache));
       ColumnVectorPtr right_result(
-          right_operand_->getAllValuesForJoin(left_relation_id,
-                                              left_accessor,
-                                              right_relation_id,
+          right_operand_->getAllValuesForJoin(left_accessor,
                                               right_accessor,
                                               joined_tuple_ids,
                                               cv_cache));

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarBinaryExpression.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarBinaryExpression.hpp b/expressions/scalar/ScalarBinaryExpression.hpp
index 4ac1f62..6f9c41d 100644
--- a/expressions/scalar/ScalarBinaryExpression.hpp
+++ b/expressions/scalar/ScalarBinaryExpression.hpp
@@ -84,10 +84,8 @@ class ScalarBinaryExpression : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   bool hasStaticValue() const override {
@@ -104,9 +102,7 @@ class ScalarBinaryExpression : public Scalar {
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarCaseExpression.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarCaseExpression.cpp b/expressions/scalar/ScalarCaseExpression.cpp
index c2af83b..39e19c6 100644
--- a/expressions/scalar/ScalarCaseExpression.cpp
+++ b/expressions/scalar/ScalarCaseExpression.cpp
@@ -247,47 +247,27 @@ TypedValue ScalarCaseExpression::getValueForSingleTuple(
 
 TypedValue ScalarCaseExpression::getValueForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (has_static_value_) {
     return static_value_.makeReferenceToThis();
   } else if (fixed_result_expression_ != nullptr) {
-    return fixed_result_expression_->getValueForJoinedTuples(left_accessor,
-                                                             left_relation_id,
-                                                             left_tuple_id,
-                                                             right_accessor,
-                                                             right_relation_id,
-                                                             right_tuple_id);
+    return fixed_result_expression_->getValueForJoinedTuples(
+        left_accessor, left_tuple_id, right_accessor, right_tuple_id);
   }
 
   for (std::vector<std::unique_ptr<Predicate>>::size_type case_idx = 0;
        case_idx < when_predicates_.size();
        ++case_idx) {
-    if (when_predicates_[case_idx]->matchesForJoinedTuples(left_accessor,
-                                                           left_relation_id,
-                                                           left_tuple_id,
-                                                           right_accessor,
-                                                           right_relation_id,
-                                                           right_tuple_id)) {
+    if (when_predicates_[case_idx]->matchesForJoinedTuples(
+            left_accessor, left_tuple_id, right_accessor, right_tuple_id)) {
       return result_expressions_[case_idx]->getValueForJoinedTuples(
-          left_accessor,
-          left_relation_id,
-          left_tuple_id,
-          right_accessor,
-          right_relation_id,
-          right_tuple_id);
+          left_accessor, left_tuple_id, right_accessor, right_tuple_id);
     }
   }
   return else_result_expression_->getValueForJoinedTuples(
-      left_accessor,
-      left_relation_id,
-      left_tuple_id,
-      right_accessor,
-      right_relation_id,
-      right_tuple_id);
+      left_accessor, left_tuple_id, right_accessor, right_tuple_id);
 }
 
 ColumnVectorPtr ScalarCaseExpression::getAllValues(
@@ -370,9 +350,7 @@ ColumnVectorPtr ScalarCaseExpression::getAllValues(
 }
 
 ColumnVectorPtr ScalarCaseExpression::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {
@@ -381,9 +359,7 @@ ColumnVectorPtr ScalarCaseExpression::getAllValuesForJoin(
         ColumnVector::MakeVectorOfValue(type_, static_value_, joined_tuple_ids.size()));
   } else if (fixed_result_expression_) {
     return fixed_result_expression_->getAllValuesForJoin(
-        left_relation_id, left_accessor,
-        right_relation_id, right_accessor,
-        joined_tuple_ids, cv_cache);
+        left_accessor, right_accessor, joined_tuple_ids, cv_cache);
   }
 
   // Slice 'joined_tuple_ids' apart by case.
@@ -418,13 +394,9 @@ ColumnVectorPtr ScalarCaseExpression::getAllValuesForJoin(
 
     const Predicate &case_predicate = *when_predicates_[case_idx];
     for (tuple_id pos : else_positions) {
-      const std::pair<tuple_id, tuple_id> check_pair = joined_tuple_ids[pos];
-      if (case_predicate.matchesForJoinedTuples(*left_accessor,
-                                                left_relation_id,
-                                                check_pair.first,
-                                                *right_accessor,
-                                                right_relation_id,
-                                                check_pair.second)) {
+      const std::pair<tuple_id, tuple_id> &check_pair = joined_tuple_ids[pos];
+      if (case_predicate.matchesForJoinedTuples(
+              *left_accessor, check_pair.first, *right_accessor, check_pair.second)) {
         current_case_positions->set(pos);
         current_case_matches.emplace_back(check_pair);
       }
@@ -439,12 +411,7 @@ ColumnVectorPtr ScalarCaseExpression::getAllValuesForJoin(
        case_idx < case_matches.size();
        ++case_idx) {
     case_results.emplace_back(result_expressions_[case_idx]->getAllValuesForJoin(
-        left_relation_id,
-        left_accessor,
-        right_relation_id,
-        right_accessor,
-        case_matches[case_idx],
-        cv_cache));
+        left_accessor, right_accessor, case_matches[case_idx], cv_cache));
   }
 
   ColumnVectorPtr else_results;
@@ -455,12 +422,7 @@ ColumnVectorPtr ScalarCaseExpression::getAllValuesForJoin(
     }
 
     else_results = else_result_expression_->getAllValuesForJoin(
-        left_relation_id,
-        left_accessor,
-        right_relation_id,
-        right_accessor,
-        else_matches,
-        cv_cache);
+        left_accessor, right_accessor, else_matches, cv_cache);
   }
 
   // Multiplex per-case results into a single ColumnVector with values in the

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarCaseExpression.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarCaseExpression.hpp b/expressions/scalar/ScalarCaseExpression.hpp
index 22acfa8..14a2666 100644
--- a/expressions/scalar/ScalarCaseExpression.hpp
+++ b/expressions/scalar/ScalarCaseExpression.hpp
@@ -101,10 +101,8 @@ class ScalarCaseExpression : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   bool hasStaticValue() const override {
@@ -129,9 +127,7 @@ class ScalarCaseExpression : public Scalar {
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarLiteral.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarLiteral.cpp b/expressions/scalar/ScalarLiteral.cpp
index 808953d..b5f5d17 100644
--- a/expressions/scalar/ScalarLiteral.cpp
+++ b/expressions/scalar/ScalarLiteral.cpp
@@ -59,9 +59,7 @@ ColumnVectorPtr ScalarLiteral::getAllValues(
 }
 
 ColumnVectorPtr ScalarLiteral::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarLiteral.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarLiteral.hpp b/expressions/scalar/ScalarLiteral.hpp
index 2a4c396..3b3b994 100644
--- a/expressions/scalar/ScalarLiteral.hpp
+++ b/expressions/scalar/ScalarLiteral.hpp
@@ -87,10 +87,8 @@ class ScalarLiteral : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override {
     return internal_literal_.makeReferenceToThis();
   }
@@ -108,9 +106,7 @@ class ScalarLiteral : public Scalar {
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarSharedExpression.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarSharedExpression.cpp b/expressions/scalar/ScalarSharedExpression.cpp
index e301116..64bfb3f 100644
--- a/expressions/scalar/ScalarSharedExpression.cpp
+++ b/expressions/scalar/ScalarSharedExpression.cpp
@@ -55,16 +55,12 @@ TypedValue ScalarSharedExpression::getValueForSingleTuple(const ValueAccessor &a
 
 TypedValue ScalarSharedExpression::getValueForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   return operand_->getValueForJoinedTuples(left_accessor,
-                                           left_relation_id,
                                            left_tuple_id,
                                            right_accessor,
-                                           right_relation_id,
                                            right_tuple_id);
 }
 
@@ -87,16 +83,12 @@ ColumnVectorPtr ScalarSharedExpression::getAllValues(
 }
 
 ColumnVectorPtr ScalarSharedExpression::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {
   if (cv_cache == nullptr) {
-    return operand_->getAllValuesForJoin(left_relation_id,
-                                         left_accessor,
-                                         right_relation_id,
+    return operand_->getAllValuesForJoin(left_accessor,
                                          right_accessor,
                                          joined_tuple_ids,
                                          cv_cache);
@@ -106,9 +98,7 @@ ColumnVectorPtr ScalarSharedExpression::getAllValuesForJoin(
   if (cv_cache->contains(share_id_)) {
     result = cv_cache->get(share_id_);
   } else {
-    result = operand_->getAllValuesForJoin(left_relation_id,
-                                           left_accessor,
-                                           right_relation_id,
+    result = operand_->getAllValuesForJoin(left_accessor,
                                            right_accessor,
                                            joined_tuple_ids,
                                            cv_cache);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarSharedExpression.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarSharedExpression.hpp b/expressions/scalar/ScalarSharedExpression.hpp
index f39c45b..ba9f32e 100644
--- a/expressions/scalar/ScalarSharedExpression.hpp
+++ b/expressions/scalar/ScalarSharedExpression.hpp
@@ -83,10 +83,8 @@ class ScalarSharedExpression : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   bool hasStaticValue() const override {
@@ -102,9 +100,7 @@ class ScalarSharedExpression : public Scalar {
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarUnaryExpression.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarUnaryExpression.cpp b/expressions/scalar/ScalarUnaryExpression.cpp
index c51e38f..be47d43 100644
--- a/expressions/scalar/ScalarUnaryExpression.cpp
+++ b/expressions/scalar/ScalarUnaryExpression.cpp
@@ -76,19 +76,15 @@ TypedValue ScalarUnaryExpression::getValueForSingleTuple(const ValueAccessor &ac
 
 TypedValue ScalarUnaryExpression::getValueForJoinedTuples(
     const ValueAccessor &left_accessor,
-    const relation_id left_relation_id,
     const tuple_id left_tuple_id,
     const ValueAccessor &right_accessor,
-    const relation_id right_relation_id,
     const tuple_id right_tuple_id) const {
   if (fast_operator_.get() == nullptr) {
     return static_value_.makeReferenceToThis();
   } else {
     return fast_operator_->applyToTypedValue(operand_->getValueForJoinedTuples(left_accessor,
-                                                                               left_relation_id,
                                                                                left_tuple_id,
                                                                                right_accessor,
-                                                                               right_relation_id,
                                                                                right_tuple_id));
   }
 }
@@ -119,9 +115,7 @@ ColumnVectorPtr ScalarUnaryExpression::getAllValues(
 }
 
 ColumnVectorPtr ScalarUnaryExpression::getAllValuesForJoin(
-    const relation_id left_relation_id,
     ValueAccessor *left_accessor,
-    const relation_id right_relation_id,
     ValueAccessor *right_accessor,
     const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
     ColumnVectorCache *cv_cache) const {
@@ -134,11 +128,9 @@ ColumnVectorPtr ScalarUnaryExpression::getAllValuesForJoin(
 #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
     const attribute_id operand_attr_id = operand_->getAttributeIdForValueAccessor();
     if (operand_attr_id != -1) {
-      const relation_id operand_relation_id = operand_->getRelationIdForValueAccessor();
-      DCHECK_NE(operand_relation_id, -1);
-      DCHECK((operand_relation_id == left_relation_id)
-             || (operand_relation_id == right_relation_id));
-      const bool using_left_relation = (operand_relation_id == left_relation_id);
+      const JoinSide join_side = operand_->join_side();
+      DCHECK(join_side != kNone);
+      const bool using_left_relation = (join_side == kLeftSide);
       ValueAccessor *operand_accessor = using_left_relation ? left_accessor
                                                             : right_accessor;
       return ColumnVectorPtr(
@@ -150,9 +142,7 @@ ColumnVectorPtr ScalarUnaryExpression::getAllValuesForJoin(
 #endif  // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
 
     ColumnVectorPtr operand_result(
-        operand_->getAllValuesForJoin(left_relation_id,
-                                      left_accessor,
-                                      right_relation_id,
+        operand_->getAllValuesForJoin(left_accessor,
                                       right_accessor,
                                       joined_tuple_ids,
                                       cv_cache));

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/ScalarUnaryExpression.hpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/ScalarUnaryExpression.hpp b/expressions/scalar/ScalarUnaryExpression.hpp
index 52edea7..a628bd0 100644
--- a/expressions/scalar/ScalarUnaryExpression.hpp
+++ b/expressions/scalar/ScalarUnaryExpression.hpp
@@ -79,10 +79,8 @@ class ScalarUnaryExpression : public Scalar {
 
   TypedValue getValueForJoinedTuples(
       const ValueAccessor &left_accessor,
-      const relation_id left_relation_id,
       const tuple_id left_tuple_id,
       const ValueAccessor &right_accessor,
-      const relation_id right_relation_id,
       const tuple_id right_tuple_id) const override;
 
   bool hasStaticValue() const override {
@@ -99,9 +97,7 @@ class ScalarUnaryExpression : public Scalar {
                                ColumnVectorCache *cv_cache) const override;
 
   ColumnVectorPtr getAllValuesForJoin(
-      const relation_id left_relation_id,
       ValueAccessor *left_accessor,
-      const relation_id right_relation_id,
       ValueAccessor *right_accessor,
       const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
       ColumnVectorCache *cv_cache) const override;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/expressions/scalar/tests/ScalarCaseExpression_unittest.cpp
----------------------------------------------------------------------
diff --git a/expressions/scalar/tests/ScalarCaseExpression_unittest.cpp b/expressions/scalar/tests/ScalarCaseExpression_unittest.cpp
index f385b74..b9b2b38 100644
--- a/expressions/scalar/tests/ScalarCaseExpression_unittest.cpp
+++ b/expressions/scalar/tests/ScalarCaseExpression_unittest.cpp
@@ -916,8 +916,8 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchConstantTest) {
       new ScalarLiteral(TypedValue(static_cast<int>(2)), int_type)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   const int kConstant = 72;
   // WHEN 1 < 2 THEN kConstant
@@ -931,8 +931,8 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchConstantTest) {
   // WHEN double_attr = other_double THEN 0
   when_predicates.emplace_back(new ComparisonPredicate(
       ComparisonFactory::GetComparison(ComparisonID::kEqual),
-      new ScalarAttribute(*sample_relation_->getAttributeById(1)),
-      new ScalarAttribute(*other_relation.getAttributeById(0))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(1), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(0), Scalar::kRightSide)));
   result_expressions.emplace_back(new ScalarLiteral(TypedValue(0), TypeFactory::GetType(kInt)));
 
   const Type &int_nullable_type = TypeFactory::GetType(kInt, true);
@@ -947,14 +947,13 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchConstantTest) {
   // Create a list of joined tuple-id pairs (just the cross-product of tuples).
   std::vector<std::pair<tuple_id, tuple_id>> joined_tuple_ids;
   for (std::size_t tuple_num = 0; tuple_num < kNumSampleTuples; ++tuple_num) {
+    // <LeftSide-tid, RightSide-tid>.
     joined_tuple_ids.emplace_back(tuple_num, 0);
     joined_tuple_ids.emplace_back(tuple_num, 1);
   }
 
   ColumnVectorPtr result_cv(case_expr.getAllValuesForJoin(
-      0,
       &sample_data_value_accessor_,
-      1,
       &other_accessor,
       joined_tuple_ids,
       nullptr /* cv_cache */));
@@ -1012,8 +1011,8 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchOnScalarAttributeTest) {
       new ScalarLiteral(TypedValue(static_cast<int>(2)), int_type)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   // WHEN 1 < 2 THEN int_attr
   when_predicates.emplace_back(new ComparisonPredicate(
@@ -1021,13 +1020,13 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchOnScalarAttributeTest) {
       new ScalarLiteral(TypedValue(static_cast<int>(1)), int_type),
       new ScalarLiteral(TypedValue(static_cast<int>(2)), int_type)));
   result_expressions.emplace_back(
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide));
 
   // WHEN double_attr = other_double THEN 0
   when_predicates.emplace_back(new ComparisonPredicate(
       ComparisonFactory::GetComparison(ComparisonID::kEqual),
-      new ScalarAttribute(*sample_relation_->getAttributeById(1)),
-      new ScalarAttribute(*other_relation.getAttributeById(0))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(1), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(0), Scalar::kRightSide)));
   result_expressions.emplace_back(new ScalarLiteral(TypedValue(0), TypeFactory::GetType(kInt)));
 
   const Type &int_nullable_type = TypeFactory::GetType(kInt, true);
@@ -1042,14 +1041,13 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchOnScalarAttributeTest) {
   // Create a list of joined tuple-id pairs (just the cross-product of tuples).
   std::vector<std::pair<tuple_id, tuple_id>> joined_tuple_ids;
   for (std::size_t tuple_num = 0; tuple_num < kNumSampleTuples; ++tuple_num) {
+    // <LeftSide-tid, RightSide-tid>.
     joined_tuple_ids.emplace_back(tuple_num, 0);
     joined_tuple_ids.emplace_back(tuple_num, 1);
   }
 
   ColumnVectorPtr result_cv(case_expr.getAllValuesForJoin(
-      0,
       &sample_data_value_accessor_,
-      1,
       &other_accessor,
       joined_tuple_ids,
       nullptr /* cv_cache */));
@@ -1116,8 +1114,8 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchTest) {
       new ScalarLiteral(TypedValue(static_cast<int>(2)), int_type)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   // WHEN 1 < 2 THEN int_attr * other_int
   when_predicates.emplace_back(new ComparisonPredicate(
@@ -1126,14 +1124,14 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchTest) {
       new ScalarLiteral(TypedValue(static_cast<int>(2)), int_type)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kMultiply),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   // WHEN double_attr = other_double THEN 0
   when_predicates.emplace_back(new ComparisonPredicate(
       ComparisonFactory::GetComparison(ComparisonID::kEqual),
-      new ScalarAttribute(*sample_relation_->getAttributeById(1)),
-      new ScalarAttribute(*other_relation.getAttributeById(0))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(1), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(0), Scalar::kRightSide)));
   result_expressions.emplace_back(new ScalarLiteral(TypedValue(0), TypeFactory::GetType(kInt)));
 
   const Type &int_nullable_type = TypeFactory::GetType(kInt, true);
@@ -1148,14 +1146,13 @@ TEST_F(ScalarCaseExpressionTest, JoinStaticBranchTest) {
   // Create a list of joined tuple-id pairs (just the cross-product of tuples).
   std::vector<std::pair<tuple_id, tuple_id>> joined_tuple_ids;
   for (std::size_t tuple_num = 0; tuple_num < kNumSampleTuples; ++tuple_num) {
+    // <LeftSide-tid, RightSide-tid>.
     joined_tuple_ids.emplace_back(tuple_num, 0);
     joined_tuple_ids.emplace_back(tuple_num, 1);
   }
 
   ColumnVectorPtr result_cv(case_expr.getAllValuesForJoin(
-      0,
       &sample_data_value_accessor_,
-      1,
       &other_accessor,
       joined_tuple_ids,
       nullptr /* cv_cache */));
@@ -1217,22 +1214,22 @@ TEST_F(ScalarCaseExpressionTest, JoinTest) {
   // WHEN double_attr > other_double THEN int_attr + other_int
   when_predicates.emplace_back(new ComparisonPredicate(
       ComparisonFactory::GetComparison(ComparisonID::kGreater),
-      new ScalarAttribute(*sample_relation_->getAttributeById(1)),
-      new ScalarAttribute(*other_relation.getAttributeById(0))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(1), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(0), Scalar::kRightSide)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   // WHEN double_attr < other_double THEN int_attr * other_int
   when_predicates.emplace_back(new ComparisonPredicate(
       ComparisonFactory::GetComparison(ComparisonID::kLess),
-      new ScalarAttribute(*sample_relation_->getAttributeById(1)),
-      new ScalarAttribute(*other_relation.getAttributeById(0))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(1), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(0), Scalar::kRightSide)));
   result_expressions.emplace_back(new ScalarBinaryExpression(
       BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kMultiply),
-      new ScalarAttribute(*sample_relation_->getAttributeById(0)),
-      new ScalarAttribute(*other_relation.getAttributeById(1))));
+      new ScalarAttribute(*sample_relation_->getAttributeById(0), Scalar::kLeftSide),
+      new ScalarAttribute(*other_relation.getAttributeById(1), Scalar::kRightSide)));
 
   // ELSE 0
   ScalarCaseExpression case_expr(
@@ -1244,14 +1241,13 @@ TEST_F(ScalarCaseExpressionTest, JoinTest) {
   // Create a list of joined tuple-id pairs (just the cross-product of tuples).
   std::vector<std::pair<tuple_id, tuple_id>> joined_tuple_ids;
   for (std::size_t tuple_num = 0; tuple_num < kNumSampleTuples; ++tuple_num) {
+    // <LeftSide-tid, RightSide-tid>.
     joined_tuple_ids.emplace_back(tuple_num, 0);
     joined_tuple_ids.emplace_back(tuple_num, 1);
   }
 
   ColumnVectorPtr result_cv(case_expr.getAllValuesForJoin(
-      0,
       &sample_data_value_accessor_,
-      1,
       &other_accessor,
       joined_tuple_ids,
       nullptr /* cv_cache */));

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/ExecutionGenerator.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/ExecutionGenerator.cpp b/query_optimizer/ExecutionGenerator.cpp
index cc1319c..b413a97 100644
--- a/query_optimizer/ExecutionGenerator.cpp
+++ b/query_optimizer/ExecutionGenerator.cpp
@@ -29,16 +29,12 @@
 #include <string>
 #include <type_traits>
 #include <unordered_map>
-
-#include "query_optimizer/QueryOptimizerConfig.h"  // For QUICKSTEP_DISTRIBUTED.
-
-#ifdef QUICKSTEP_DISTRIBUTED
 #include <unordered_set>
-#endif
-
 #include <utility>
 #include <vector>
 
+#include "query_optimizer/QueryOptimizerConfig.h"  // For QUICKSTEP_DISTRIBUTED.
+
 #ifdef QUICKSTEP_DISTRIBUTED
 #include "catalog/Catalog.pb.h"
 #endif
@@ -72,6 +68,7 @@
 #include "query_optimizer/expressions/Alias.hpp"
 #include "query_optimizer/expressions/AttributeReference.hpp"
 #include "query_optimizer/expressions/ComparisonExpression.hpp"
+#include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/ExpressionType.hpp"
 #include "query_optimizer/expressions/PatternMatcher.hpp"
 #include "query_optimizer/expressions/Scalar.hpp"
@@ -573,7 +570,9 @@ void ExecutionGenerator::dropAllTemporaryRelations() {
 
 void ExecutionGenerator::convertNamedExpressions(
     const std::vector<E::NamedExpressionPtr> &named_expressions,
-    S::QueryContext::ScalarGroup *scalar_group_proto) {
+    S::QueryContext::ScalarGroup *scalar_group_proto,
+    const std::unordered_set<E::ExprId> &left_expr_ids,
+    const std::unordered_set<E::ExprId> &right_expr_ids) {
   for (const E::NamedExpressionPtr &project_expression : named_expressions) {
     unique_ptr<const Scalar> execution_scalar;
     E::AliasPtr alias;
@@ -583,9 +582,11 @@ void ExecutionGenerator::convertNamedExpressions(
       // so all child expressions of an Alias should be a Scalar.
       CHECK(E::SomeScalar::MatchesWithConditionalCast(alias->expression(), &scalar))
           << alias->toString();
-      execution_scalar.reset(scalar->concretize(attribute_substitution_map_));
+      execution_scalar.reset(
+          scalar->concretize(attribute_substitution_map_, left_expr_ids, right_expr_ids));
     } else {
-      execution_scalar.reset(project_expression->concretize(attribute_substitution_map_));
+      execution_scalar.reset(
+          project_expression->concretize(attribute_substitution_map_, left_expr_ids, right_expr_ids));
     }
 
     scalar_group_proto->add_scalars()->MergeFrom(execution_scalar->getProto());
@@ -593,8 +594,10 @@ void ExecutionGenerator::convertNamedExpressions(
 }
 
 Predicate* ExecutionGenerator::convertPredicate(
-    const expressions::PredicatePtr &optimizer_predicate) const {
-  return optimizer_predicate->concretize(attribute_substitution_map_);
+    const expressions::PredicatePtr &optimizer_predicate,
+    const std::unordered_set<E::ExprId> &left_expr_ids,
+    const std::unordered_set<E::ExprId> &right_expr_ids) const {
+  return optimizer_predicate->concretize(attribute_substitution_map_, left_expr_ids, right_expr_ids);
 }
 
 void ExecutionGenerator::convertTableReference(
@@ -941,12 +944,27 @@ void ExecutionGenerator::convertHashJoin(const P::HashJoinPtr &physical_plan) {
     key_types.push_back(&left_attribute_type);
   }
 
+  std::unordered_set<E::ExprId> probe_expr_ids;
+  const auto probe_output_attributes = probe_physical->getOutputAttributes();
+  probe_expr_ids.reserve(probe_output_attributes.size());
+  for (const auto &probe_output_attribute : probe_output_attributes) {
+    probe_expr_ids.insert(probe_output_attribute->id());
+  }
+
+  std::unordered_set<E::ExprId> build_expr_ids;
+  const auto build_output_attributes = build_physical->getOutputAttributes();
+  build_expr_ids.reserve(build_output_attributes.size());
+  for (const auto &build_output_attribute : build_output_attributes) {
+    build_expr_ids.insert(build_output_attribute->id());
+  }
+
   // Convert the residual predicate proto.
   QueryContext::predicate_id residual_predicate_index = QueryContext::kInvalidPredicateId;
   if (physical_plan->residual_predicate()) {
     residual_predicate_index = query_context_proto_->predicates_size();
 
-    unique_ptr<const Predicate> residual_predicate(convertPredicate(physical_plan->residual_predicate()));
+    unique_ptr<const Predicate> residual_predicate(
+        convertPredicate(physical_plan->residual_predicate(), probe_expr_ids, build_expr_ids));
     query_context_proto_->add_predicates()->MergeFrom(residual_predicate->getProto());
   }
 
@@ -955,7 +973,8 @@ void ExecutionGenerator::convertHashJoin(const P::HashJoinPtr &physical_plan) {
   if (physical_plan->build_predicate()) {
     build_predicate_index = query_context_proto_->predicates_size();
 
-    unique_ptr<const Predicate> build_predicate(convertPredicate(physical_plan->build_predicate()));
+    unique_ptr<const Predicate> build_predicate(
+        convertPredicate(physical_plan->build_predicate(), probe_expr_ids, build_expr_ids));
     query_context_proto_->add_predicates()->MergeFrom(build_predicate->getProto());
   }
 
@@ -963,7 +982,7 @@ void ExecutionGenerator::convertHashJoin(const P::HashJoinPtr &physical_plan) {
   const QueryContext::scalar_group_id project_expressions_group_index =
       query_context_proto_->scalar_groups_size();
   convertNamedExpressions(physical_plan->project_expressions(),
-                          query_context_proto_->add_scalar_groups());
+                          query_context_proto_->add_scalar_groups(), probe_expr_ids, build_expr_ids);
 
   const CatalogRelationInfo *build_relation_info =
       findRelationInfoOutputByPhysical(build_physical);
@@ -979,19 +998,12 @@ void ExecutionGenerator::convertHashJoin(const P::HashJoinPtr &physical_plan) {
         new std::vector<bool>(
             E::MarkExpressionsReferingAnyAttribute(
                 physical_plan->project_expressions(),
-                build_physical->getOutputAttributes())));
+                build_output_attributes)));
   }
 
   const CatalogRelation *build_relation = build_relation_info->relation;
   const CatalogRelation *probe_relation = probe_relation_info->relation;
 
-  // FIXME(quickstep-team): Add support for self-join.
-  // We check to see if the build_predicate is null as certain queries that
-  // support hash-select fuse will result in the first check being true.
-  if (build_relation == probe_relation && physical_plan->build_predicate() == nullptr) {
-    THROW_SQL_ERROR() << "Self-join is not supported";
-  }
-
   // Create join hash table proto.
   const QueryContext::join_hash_table_id join_hash_table_index =
       query_context_proto_->join_hash_tables_size();
@@ -1129,10 +1141,28 @@ void ExecutionGenerator::convertNestedLoopsJoin(
     const P::NestedLoopsJoinPtr &physical_plan) {
   // NestedLoopsJoin is converted to a NestedLoopsJoin operator.
 
+  const P::PhysicalPtr &left_physical = physical_plan->left();
+  const P::PhysicalPtr &right_physical = physical_plan->right();
+
+  std::unordered_set<E::ExprId> left_expr_ids;
+  const auto left_output_attributes = left_physical->getOutputAttributes();
+  left_expr_ids.reserve(left_output_attributes.size());
+  for (const auto &left_output_attribute : left_output_attributes) {
+    left_expr_ids.insert(left_output_attribute->id());
+  }
+
+  std::unordered_set<E::ExprId> right_expr_ids;
+  const auto right_output_attributes = right_physical->getOutputAttributes();
+  right_expr_ids.reserve(right_output_attributes.size());
+  for (const auto &right_output_attribute : right_output_attributes) {
+    right_expr_ids.insert(right_output_attribute->id());
+  }
+
   // Convert the join predicate proto.
   const QueryContext::predicate_id execution_join_predicate_index = query_context_proto_->predicates_size();
   if (physical_plan->join_predicate()) {
-    unique_ptr<const Predicate> execution_join_predicate(convertPredicate(physical_plan->join_predicate()));
+    unique_ptr<const Predicate> execution_join_predicate(
+        convertPredicate(physical_plan->join_predicate(), left_expr_ids, right_expr_ids));
     query_context_proto_->add_predicates()->MergeFrom(execution_join_predicate->getProto());
   } else {
     query_context_proto_->add_predicates()->set_predicate_type(S::Predicate::TRUE);
@@ -1142,20 +1172,16 @@ void ExecutionGenerator::convertNestedLoopsJoin(
   const QueryContext::scalar_group_id project_expressions_group_index =
       query_context_proto_->scalar_groups_size();
   convertNamedExpressions(physical_plan->project_expressions(),
-                          query_context_proto_->add_scalar_groups());
+                          query_context_proto_->add_scalar_groups(),
+                          left_expr_ids, right_expr_ids);
 
   const CatalogRelationInfo *left_relation_info =
-      findRelationInfoOutputByPhysical(physical_plan->left());
+      findRelationInfoOutputByPhysical(left_physical);
   const CatalogRelation &left_relation = *left_relation_info->relation;
   const CatalogRelationInfo *right_relation_info =
-      findRelationInfoOutputByPhysical(physical_plan->right());
+      findRelationInfoOutputByPhysical(right_physical);
   const CatalogRelation &right_relation = *right_relation_info->relation;
 
-  // FIXME(quickstep-team): Add support for self-join.
-  if (left_relation.getID() == right_relation.getID()) {
-    THROW_SQL_ERROR() << "NestedLoopsJoin does not support self-join yet";
-  }
-
   const std::size_t num_partitions = left_relation.getNumPartitions();
 
 #ifdef QUICKSTEP_DEBUG

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/ExecutionGenerator.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/ExecutionGenerator.hpp b/query_optimizer/ExecutionGenerator.hpp
index bc9f88b..1385757 100644
--- a/query_optimizer/ExecutionGenerator.hpp
+++ b/query_optimizer/ExecutionGenerator.hpp
@@ -24,11 +24,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
-
-#ifdef QUICKSTEP_DISTRIBUTED
 #include <unordered_set>
-#endif
-
 #include <vector>
 
 #include "catalog/CatalogTypedefs.hpp"
@@ -388,10 +384,16 @@ class ExecutionGenerator {
    * @param named_expressions The list of NamedExpressions to be converted.
    * @param scalar_group_proto The corresponding scalars proto in QueryContext
    *        proto.
+   * @param left_expr_ids The ExprIds from the left hand side.
+   * @param right_expr_ids The ExprIds from the right hand side.
    */
   void convertNamedExpressions(
       const std::vector<expressions::NamedExpressionPtr> &named_expressions,
-      serialization::QueryContext::ScalarGroup *scalar_group_proto);
+      serialization::QueryContext::ScalarGroup *scalar_group_proto,
+      const std::unordered_set<expressions::ExprId> &left_expr_ids =
+          std::unordered_set<expressions::ExprId>(),
+      const std::unordered_set<expressions::ExprId> &right_expr_ids =
+          std::unordered_set<expressions::ExprId>());
 
   /**
    * @brief Converts a Predicate in the optimizer expression system to a
@@ -399,9 +401,16 @@ class ExecutionGenerator {
    *        takes ownership of the returned pointer.
    *
    * @param optimizer_predicate The Predicate to be converted.
+   * @param left_expr_ids The ExprIds from the left hand side.
+   * @param right_expr_ids The ExprIds from the right hand side.
    * @return The corresponding Predicate in the execution expression system.
    */
-  Predicate* convertPredicate(const expressions::PredicatePtr &optimizer_predicate) const;
+  Predicate* convertPredicate(
+      const expressions::PredicatePtr &optimizer_predicate,
+      const std::unordered_set<expressions::ExprId> &left_expr_ids =
+          std::unordered_set<expressions::ExprId>(),
+      const std::unordered_set<expressions::ExprId> &right_expr_ids =
+          std::unordered_set<expressions::ExprId>()) const;
 
   /**
    * @brief Drops all temporary relations created by the generator

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/expressions/Alias.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/Alias.cpp b/query_optimizer/expressions/Alias.cpp
index f2b2795..0e3541d 100644
--- a/query_optimizer/expressions/Alias.cpp
+++ b/query_optimizer/expressions/Alias.cpp
@@ -21,6 +21,7 @@
 
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "catalog/CatalogTypedefs.hpp"
@@ -65,7 +66,9 @@ ExpressionPtr Alias::copyWithNewChildren(
 }
 
 ::quickstep::Scalar *Alias::concretize(
-    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const {
+    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map,
+    const std::unordered_set<ExprId> &left_expr_ids,
+    const std::unordered_set<ExprId> &right_expr_ids) const {
   // Alias should be converted to a CatalogAttribute.
   LOG(FATAL) << "Cannot concretize Alias to a scalar for evaluation";
 }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/expressions/Alias.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/Alias.hpp b/query_optimizer/expressions/Alias.hpp
index e0ee959..16d3715 100644
--- a/query_optimizer/expressions/Alias.hpp
+++ b/query_optimizer/expressions/Alias.hpp
@@ -23,6 +23,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "query_optimizer/OptimizerTree.hpp"
@@ -81,7 +82,9 @@ class Alias : public NamedExpression {
   }
 
   ::quickstep::Scalar *concretize(
-      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override;
+      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map,
+      const std::unordered_set<ExprId> &left_expr_ids = std::unordered_set<ExprId>(),
+      const std::unordered_set<ExprId> &right_expr_ids = std::unordered_set<ExprId>()) const override;
 
   /**
    * @brief Creates an immutable Alias. If \p expression is also an Alias,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/expressions/AttributeReference.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/AttributeReference.cpp b/query_optimizer/expressions/AttributeReference.cpp
index facfb39..86a1711 100644
--- a/query_optimizer/expressions/AttributeReference.cpp
+++ b/query_optimizer/expressions/AttributeReference.cpp
@@ -23,8 +23,10 @@
 #include <functional>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
+#include "expressions/scalar/Scalar.hpp"
 #include "expressions/scalar/ScalarAttribute.hpp"
 #include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/Expression.hpp"
@@ -53,11 +55,22 @@ std::vector<AttributeReferencePtr> AttributeReference::getReferencedAttributes()
 }
 
 ::quickstep::Scalar *AttributeReference::concretize(
-    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const {
+    const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map,
+    const std::unordered_set<ExprId> &left_expr_ids,
+    const std::unordered_set<ExprId> &right_expr_ids) const {
+  const ExprId expr_id = id();
   const std::unordered_map<ExprId, const CatalogAttribute*>::const_iterator found_it =
-      substitution_map.find(id());
+      substitution_map.find(expr_id);
   DCHECK(found_it != substitution_map.end()) << toString();
-  return new ::quickstep::ScalarAttribute(*found_it->second);
+
+  ::quickstep::Scalar::JoinSide join_side = ::quickstep::Scalar::kNone;
+  if (left_expr_ids.find(expr_id) != left_expr_ids.end()) {
+    join_side = ::quickstep::Scalar::kLeftSide;
+  } else if (right_expr_ids.find(expr_id) != right_expr_ids.end()) {
+    join_side = ::quickstep::Scalar::kRightSide;
+  }
+
+  return new ::quickstep::ScalarAttribute(*found_it->second, join_side);
 }
 
 std::size_t AttributeReference::computeHash() const {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8b7c3801/query_optimizer/expressions/AttributeReference.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/AttributeReference.hpp b/query_optimizer/expressions/AttributeReference.hpp
index ca796ba..0a8b855 100644
--- a/query_optimizer/expressions/AttributeReference.hpp
+++ b/query_optimizer/expressions/AttributeReference.hpp
@@ -24,6 +24,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "catalog/CatalogTypedefs.hpp"
@@ -88,7 +89,9 @@ class AttributeReference : public NamedExpression {
   std::vector<AttributeReferencePtr> getReferencedAttributes() const override;
 
   ::quickstep::Scalar* concretize(
-      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override;
+      const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map,
+      const std::unordered_set<ExprId> &left_expr_ids = std::unordered_set<ExprId>(),
+      const std::unordered_set<ExprId> &right_expr_ids = std::unordered_set<ExprId>()) const override;
 
   bool equals(const ScalarPtr &other) const override;