blob: 8781750f8e9c769df0e10b7c78c86ee2f2a08dc3 [file] [log] [blame]
/**
* 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