Skip to content
This repository has been archived by the owner on Sep 27, 2019. It is now read-only.

Commit

Permalink
Merge pull request #1 from 17zhangw/erik_short_circuit
Browse files Browse the repository at this point in the history
Merge short circuit rules & hand-fed catalog rules into equiv-experimental
  • Loading branch information
Erik Sargent authored May 5, 2019
2 parents f4bf21c + 6578dca commit c55babe
Show file tree
Hide file tree
Showing 8 changed files with 579 additions and 1 deletion.
17 changes: 17 additions & 0 deletions src/binder/bind_node_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "binder/bind_node_visitor.h"
#include "catalog/catalog.h"
#include "catalog/table_catalog.h"
#include "catalog/column_catalog.h"
#include "expression/expression_util.h"
#include "expression/star_expression.h"
#include "type/type_id.h"
Expand Down Expand Up @@ -250,6 +252,21 @@ void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
expr->SetColName(col_name);
expr->SetValueType(value_type);
expr->SetBoundOid(col_pos_tuple);

// TODO(esargent): Uncommenting the following code makes AddressSanitizer get mad at me with a
// heap buffer overflow whenever I try a query that references the same non-null attribute multiple
// times (e.g. 'SELECT id FROM t WHERE id < 3 AND id > 1'). Leaving it commented out prevents the
// memory error, but then this prevents the is_not_null flag of a tuple expression from being
// populated in some cases (specifically, when the expression's table name is initially empty).

//if (table_obj == nullptr) {
// LOG_DEBUG("Extracting regular table object");
// BinderContext::GetRegularTableObj(context_, table_name, table_obj, depth);
//}

if (table_obj != nullptr) {
expr->SetIsNotNull(table_obj->GetColumnCatalogEntry(std::get<2>(col_pos_tuple), false)->IsNotNull());
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/include/common/internal_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,14 @@ enum class RuleType : uint32_t {
TV_EQUALITY_WITH_TWO_CV, // (A.B = x) AND (A.B = y) where x/y are constant
TRANSITIVE_CLOSURE_CONSTANT, // (A.B = x) AND (A.B = C.D)

// Boolean short-circuit rules
AND_SHORT_CIRCUIT, // (FALSE AND B)
OR_SHORT_CIRCUIT, // (TRUE OR B)

// Catalog-based NULL/NON-NULL rules
NULL_LOOKUP_ON_NOT_NULL_COLUMN,
NOT_NULL_LOOKUP_ON_NOT_NULL_COLUMN,

// Place holder to generate number of rules compile time
NUM_RULES

Expand Down
12 changes: 11 additions & 1 deletion src/include/expression/tuple_value_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class TupleValueExpression : public AbstractExpression {
tuple_idx_ = tuple_idx;
}

inline void SetIsNotNull(bool is_not_null) {
is_not_null_ = is_not_null;
}

/**
* @brief Attribute binding
* @param binding_contexts
Expand Down Expand Up @@ -116,6 +120,8 @@ class TupleValueExpression : public AbstractExpression {
if ((table_name_.empty() xor other.table_name_.empty()) ||
col_name_.empty() xor other.col_name_.empty())
return false;
if (GetIsNotNull() != other.GetIsNotNull())
return false;
bool res = bound_obj_id_ == other.bound_obj_id_;
if (!table_name_.empty() && !other.table_name_.empty())
res = table_name_ == other.table_name_ && res;
Expand Down Expand Up @@ -151,6 +157,8 @@ class TupleValueExpression : public AbstractExpression {

bool GetIsBound() const { return is_bound_; }

bool GetIsNotNull() const { return is_not_null_; }

const std::tuple<oid_t, oid_t, oid_t> &GetBoundOid() const {
return bound_obj_id_;
}
Expand Down Expand Up @@ -185,7 +193,8 @@ class TupleValueExpression : public AbstractExpression {
value_idx_(other.value_idx_),
tuple_idx_(other.tuple_idx_),
table_name_(other.table_name_),
col_name_(other.col_name_) {}
col_name_(other.col_name_),
is_not_null_(other.is_not_null_) {}

// Bound flag
bool is_bound_ = false;
Expand All @@ -196,6 +205,7 @@ class TupleValueExpression : public AbstractExpression {
int tuple_idx_;
std::string table_name_;
std::string col_name_;
bool is_not_null_ = false;

const planner::AttributeInfo *ai_;
};
Expand Down
45 changes: 45 additions & 0 deletions src/include/optimizer/rule_rewrite.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,50 @@ class TransitiveClosureConstantTransform: public Rule<AbsExpr_Container,Expressi
OptimizeContextTemplate *context) const override;
};

class AndShortCircuit: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
public:
AndShortCircuit();

int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
void Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const override;
};

class OrShortCircuit: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
public:
OrShortCircuit();

int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
void Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const override;
};

class NullLookupOnNotNullColumn: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
public:
NullLookupOnNotNullColumn();

int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
void Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const override;
};

class NotNullLookupOnNotNullColumn: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
public:
NotNullLookupOnNotNullColumn();

int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
void Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const override;
};


} // namespace optimizer
} // namespace peloton
5 changes: 5 additions & 0 deletions src/optimizer/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@

#include "optimizer/binding.h"

#include <memory>

#include "common/logger.h"
#include "optimizer/operator_visitor.h"
#include "optimizer/optimizer.h"
#include "optimizer/absexpr_expression.h"
#include "expression/group_marker_expression.h"
#include "expression/abstract_expression.h"
#include "expression/tuple_value_expression.h"

namespace peloton {
namespace optimizer {
Expand Down Expand Up @@ -134,6 +138,7 @@ GroupExprBindingIterator<Node,OperatorType,OperatorExpr>::GroupExprBindingIterat
first_(true),
has_next_(false),
current_binding_(std::make_shared<OperatorExpr>(gexpr->Op())) {
// First check to make sure that types of pattern & expression match
if (gexpr->Op().GetType() != pattern->Type()) {
return;
}
Expand Down
6 changes: 6 additions & 0 deletions src/optimizer/rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ RuleSet<AbsExpr_Container,ExpressionType,AbsExpr_Expression>::RuleSet() {
// Additional rules
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new TVEqualityWithTwoCVTransform());
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new TransitiveClosureConstantTransform());

AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new AndShortCircuit());
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new OrShortCircuit());

AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new NullLookupOnNotNullColumn());
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new NotNullLookupOnNotNullColumn());
}

template <>
Expand Down
208 changes: 208 additions & 0 deletions src/optimizer/rule_rewrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,5 +397,213 @@ void TransitiveClosureConstantTransform::Transform(std::shared_ptr<AbsExpr_Expre
transformed.push_back(abs_expr);
}

// ===========================================================
//
// Boolean short-circuit related functions
//
// ===========================================================
AndShortCircuit::AndShortCircuit() {
type_ = RuleType::AND_SHORT_CIRCUIT;

// (FALSE AND <any expression>)
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::CONJUNCTION_AND);
auto left_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_CONSTANT);
auto right_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::GROUP_MARKER);

match_pattern->AddChild(left_child);
match_pattern->AddChild(right_child);
}

int AndShortCircuit::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
(void)group_expr;
(void)context;
return static_cast<int>(RulePriority::HIGH);
}

bool AndShortCircuit::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
(void)plan;
(void)context;
return true;
}

void AndShortCircuit::Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const {
(void)context;
(void)transformed;

// Asserting guarantees provided by the GroupExprBindingIterator
// Structure: (FALSE AND <any expression>)
PELOTON_ASSERT(input->Children().size() == 2);
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_AND);

std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
PELOTON_ASSERT(left->Children().size() == 0);
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);

std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
type::Value left_value = left_cv_expr->GetValue();

// Only transform the expression if we're ANDing a FALSE boolean value
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsFalse()) {
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
std::shared_ptr<expression::ConstantValueExpression> false_expr = std::make_shared<expression::ConstantValueExpression>(val_false);
std::shared_ptr<AbsExpr_Expression> false_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(false_expr));
transformed.push_back(false_container);
}
}


OrShortCircuit::OrShortCircuit() {
type_ = RuleType::OR_SHORT_CIRCUIT;

// (FALSE AND <any expression>)
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::CONJUNCTION_OR);
auto left_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_CONSTANT);
auto right_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::GROUP_MARKER);

match_pattern->AddChild(left_child);
match_pattern->AddChild(right_child);
}

int OrShortCircuit::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
(void)group_expr;
(void)context;
return static_cast<int>(RulePriority::HIGH);
}

bool OrShortCircuit::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
(void)plan;
(void)context;
return true;
}

void OrShortCircuit::Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const {
(void)context;
(void)transformed;

// Asserting guarantees provided by the GroupExprBindingIterator
// Structure: (TRUE OR <any expression>)
PELOTON_ASSERT(input->Children().size() == 2);
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_OR);

std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
PELOTON_ASSERT(left->Children().size() == 0);
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);

std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
type::Value left_value = left_cv_expr->GetValue();

// Only transform the expression if we're ANDing a TRUE boolean value
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsTrue()) {
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
std::shared_ptr<expression::ConstantValueExpression> true_expr = std::make_shared<expression::ConstantValueExpression>(val_true);
std::shared_ptr<AbsExpr_Expression> true_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(true_expr));
transformed.push_back(true_container);
}
}


NullLookupOnNotNullColumn::NullLookupOnNotNullColumn() {
type_ = RuleType::NULL_LOOKUP_ON_NOT_NULL_COLUMN;

// Structure: [T.X IS NULL]
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::OPERATOR_IS_NULL);
auto child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_TUPLE);

match_pattern->AddChild(child);
}

int NullLookupOnNotNullColumn::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
(void)group_expr;
(void)context;
return static_cast<int>(RulePriority::HIGH);
}

bool NullLookupOnNotNullColumn::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
(void)plan;
(void)context;
return true;
}

void NullLookupOnNotNullColumn::Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const {
(void)context;
(void)transformed;

// Asserting guarantees provided by the GroupExprBindingIterator
// Structure: (TRUE OR <any expression>)
PELOTON_ASSERT(input->Children().size() == 1);
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::OPERATOR_IS_NULL);

std::shared_ptr<AbsExpr_Expression> child = input->Children()[0];
PELOTON_ASSERT(child->Children().size() == 0);
PELOTON_ASSERT(child->Op().GetType() == ExpressionType::VALUE_TUPLE);

std::shared_ptr<expression::TupleValueExpression> tuple_expr = std::dynamic_pointer_cast<expression::TupleValueExpression>(child->Op().GetExpr());

// Only transform into [FALSE] if the tuple value expression is specifically non-NULL,
// otherwise do nothing
if (tuple_expr->GetIsNotNull()) {
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
std::shared_ptr<expression::ConstantValueExpression> false_expr = std::make_shared<expression::ConstantValueExpression>(val_false);
std::shared_ptr<AbsExpr_Expression> false_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(false_expr));
transformed.push_back(false_container);
}
}


NotNullLookupOnNotNullColumn::NotNullLookupOnNotNullColumn() {
type_ = RuleType::NOT_NULL_LOOKUP_ON_NOT_NULL_COLUMN;

// Structure: [T.X IS NOT NULL]
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::OPERATOR_IS_NOT_NULL);
auto child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_TUPLE);

match_pattern->AddChild(child);
}

int NotNullLookupOnNotNullColumn::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
(void)group_expr;
(void)context;
return static_cast<int>(RulePriority::HIGH);
}

bool NotNullLookupOnNotNullColumn::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
(void)plan;
(void)context;
return true;
}

void NotNullLookupOnNotNullColumn::Transform(std::shared_ptr<AbsExpr_Expression> input,
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
OptimizeContextTemplate *context) const {
(void)context;
(void)transformed;

// Asserting guarantees provided by the GroupExprBindingIterator
// Structure: (TRUE OR <any expression>)
PELOTON_ASSERT(input->Children().size() == 1);
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::OPERATOR_IS_NOT_NULL);

std::shared_ptr<AbsExpr_Expression> child = input->Children()[0];
PELOTON_ASSERT(child->Children().size() == 0);
PELOTON_ASSERT(child->Op().GetType() == ExpressionType::VALUE_TUPLE);

std::shared_ptr<expression::TupleValueExpression> tuple_expr = std::dynamic_pointer_cast<expression::TupleValueExpression>(child->Op().GetExpr());

// Only transform into [TRUE] if the tuple value expression is specifically non-NULL,
// otherwise do nothing
if (tuple_expr->GetIsNotNull()) {
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
std::shared_ptr<expression::ConstantValueExpression> true_expr = std::make_shared<expression::ConstantValueExpression>(val_true);
std::shared_ptr<AbsExpr_Expression> true_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(true_expr));
transformed.push_back(true_container);
}
}

} // namespace optimizer
} // namespace peloton
Loading

0 comments on commit c55babe

Please sign in to comment.