| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| **/ |
| |
| #include "query_optimizer/rules/PruneColumns.hpp" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "query_optimizer/expressions/AttributeReference.hpp" |
| #include "query_optimizer/expressions/NamedExpression.hpp" |
| #include "query_optimizer/expressions/Predicate.hpp" |
| #include "query_optimizer/expressions/PredicateLiteral.hpp" |
| #include "query_optimizer/physical/HashJoin.hpp" |
| #include "query_optimizer/physical/NestedLoopsJoin.hpp" |
| #include "query_optimizer/physical/Physical.hpp" |
| #include "query_optimizer/physical/Selection.hpp" |
| #include "query_optimizer/physical/TableReference.hpp" |
| #include "query_optimizer/physical/TopLevelPlan.hpp" |
| #include "query_optimizer/rules/Rule.hpp" |
| #include "query_optimizer/rules/tests/PhysicalRuleTest.hpp" |
| #include "query_optimizer/rules/tests/RuleTest.hpp" |
| #include "utility/Cast.hpp" |
| #include "utility/Macros.hpp" |
| |
| #include "glog/logging.h" |
| #include "gtest/gtest.h" |
| |
| namespace quickstep { |
| namespace optimizer { |
| |
| namespace E = ::quickstep::optimizer::expressions; |
| namespace P = ::quickstep::optimizer::physical; |
| |
| class PruneColumnTest : public PhysicalRuleTest { |
| protected: |
| PruneColumnTest() : PhysicalRuleTest() {} |
| |
| ~PruneColumnTest() override {} |
| |
| void SetUp() override { |
| PhysicalRuleTest::SetUp(); |
| trivial_selection_0_ = |
| P::Selection::Create(physical_table_reference_0_, |
| CastSharedPtrVector<E::NamedExpression>( |
| physical_table_reference_0_->getOutputAttributes()), |
| E::PredicatePtr()); |
| trivial_selection_1_ = |
| P::Selection::Create(physical_table_reference_1_, |
| CastSharedPtrVector<E::NamedExpression>( |
| physical_table_reference_1_->getOutputAttributes()), |
| E::PredicatePtr()); |
| } |
| |
| void setupRule(std::unique_ptr<Rule<P::Physical>> *rule) override { |
| rule->reset(new PruneColumns()); |
| } |
| |
| // Two trivial Selections that simply project all attributes with no filtering |
| // predicates. |
| P::SelectionPtr trivial_selection_0_; |
| P::SelectionPtr trivial_selection_1_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PruneColumnTest); |
| }; |
| |
| TEST_F(PruneColumnTest, PrimaryTest) { |
| std::vector<E::NamedExpressionPtr> project_expressions_with_redundancy = |
| trivial_selection_0_->project_expressions(); |
| const std::vector<E::NamedExpressionPtr> project_expressions_from_selection_1 = |
| trivial_selection_1_->project_expressions(); |
| project_expressions_with_redundancy.insert(project_expressions_with_redundancy.end(), |
| project_expressions_from_selection_1.begin(), |
| project_expressions_from_selection_1.end()); |
| |
| // Hash join on the two trivial Selections with all attributes being output. |
| const P::HashJoinPtr hash_join = P::HashJoin::Create(trivial_selection_0_, |
| trivial_selection_1_, |
| {relation_attribute_reference_0_0_}, |
| {relation_attribute_reference_1_0_}, |
| E::PredicatePtr(), |
| project_expressions_with_redundancy, |
| P::HashJoin::JoinType::kInnerJoin); |
| |
| // alias_add_literal_0_: relation_attribute_reference_0_0_ + literal_0_. |
| // filter_predicate_1_: relation_attribute_reference_1_0_ > literal_0_. |
| const P::SelectionPtr selection = P::Selection::Create(hash_join, |
| {alias_add_literal_0_} /* project_expressions */, |
| filter_predicate_1_); |
| input_ = P::TopLevelPlan::Create(selection); |
| |
| const P::SelectionPtr pruned_selection_0 = P::Selection::Create( |
| physical_table_reference_0_, |
| {relation_attribute_reference_0_0_} /* project_expressions */, |
| E::PredicatePtr()); |
| const P::SelectionPtr pruned_selection_1 = P::Selection::Create( |
| physical_table_reference_1_, |
| {relation_attribute_reference_1_0_} /* project_expressions */, |
| E::PredicatePtr()); |
| |
| const std::vector<E::NamedExpressionPtr> pruned_project_expressions_for_join{ |
| relation_attribute_reference_0_0_, relation_attribute_reference_1_0_}; |
| |
| const P::HashJoinPtr new_hash_join = P::HashJoin::Create( |
| pruned_selection_0, |
| pruned_selection_1, |
| {relation_attribute_reference_0_0_}, |
| {relation_attribute_reference_1_0_}, |
| E::PredicatePtr(), |
| pruned_project_expressions_for_join, |
| P::HashJoin::JoinType::kInnerJoin); |
| const P::SelectionPtr new_selection = std::static_pointer_cast<const P::Selection>( |
| selection->copyWithNewChildren({new_hash_join} /* new_children */)); |
| expect_output_ = P::TopLevelPlan::Create(new_selection); |
| |
| APPLY_RULE_AND_CHECK_OUTPUT(); |
| } |
| |
| TEST_F(PruneColumnTest, EmptyProjection) { |
| // When we apply the PruneColumns rule, it is possible that all the project |
| // expressions are removed from one physical node. |
| |
| std::vector<E::NamedExpressionPtr> project_expressions_with_redundancy = |
| trivial_selection_0_->project_expressions(); |
| const std::vector<E::NamedExpressionPtr> project_expressions_from_selection_1 = |
| trivial_selection_1_->project_expressions(); |
| project_expressions_with_redundancy.insert(project_expressions_with_redundancy.end(), |
| project_expressions_from_selection_1.begin(), |
| project_expressions_from_selection_1.end()); |
| |
| // Cross product trivial_selection_0_ and trivial_selection_1_. |
| const P::NestedLoopsJoinPtr cartesian_join = P::NestedLoopsJoin::Create( |
| trivial_selection_0_, |
| trivial_selection_1_, |
| E::PredicateLiteral::Create(true), |
| project_expressions_with_redundancy); |
| |
| // Only relation_attribute_reference_0_0_ for table_0 is used in the |
| // Selection. |
| const P::SelectionPtr selection = P::Selection::Create( |
| cartesian_join, |
| {alias_add_literal_0_} /* project_expressions */, |
| E::PredicatePtr()); |
| input_ = P::TopLevelPlan::Create(selection); |
| |
| const P::SelectionPtr pruned_selection_0 = P::Selection::Create( |
| physical_table_reference_0_, |
| {relation_attribute_reference_0_0_} /* project_expressions */, |
| E::PredicatePtr()); |
| // Empty project expression list. |
| const P::SelectionPtr pruned_selection_1 = P::Selection::Create( |
| physical_table_reference_1_, |
| {} /* project_expressions */, |
| E::PredicatePtr()); |
| const P::NestedLoopsJoinPtr new_cartesian_join = P::NestedLoopsJoin::Create( |
| pruned_selection_0, |
| pruned_selection_1, |
| E::PredicateLiteral::Create(true), |
| {relation_attribute_reference_0_0_} /* project_expressions */); |
| const P::SelectionPtr new_selection = std::static_pointer_cast<const P::Selection>( |
| selection->copyWithNewChildren({new_cartesian_join} /* new_children */)); |
| expect_output_ = P::TopLevelPlan::Create(new_selection); |
| |
| APPLY_RULE_AND_CHECK_OUTPUT(); |
| } |
| |
| } // namespace optimizer |
| } // namespace quickstep |