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

Commit c55babe

Browse files
author
Erik Sargent
authored
Merge pull request #1 from 17zhangw/erik_short_circuit
Merge short circuit rules & hand-fed catalog rules into equiv-experimental
2 parents f4bf21c + 6578dca commit c55babe

File tree

8 files changed

+579
-1
lines changed

8 files changed

+579
-1
lines changed

Diff for: src/binder/bind_node_visitor.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "binder/bind_node_visitor.h"
1414
#include "catalog/catalog.h"
15+
#include "catalog/table_catalog.h"
16+
#include "catalog/column_catalog.h"
1517
#include "expression/expression_util.h"
1618
#include "expression/star_expression.h"
1719
#include "type/type_id.h"
@@ -250,6 +252,21 @@ void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
250252
expr->SetColName(col_name);
251253
expr->SetValueType(value_type);
252254
expr->SetBoundOid(col_pos_tuple);
255+
256+
// TODO(esargent): Uncommenting the following code makes AddressSanitizer get mad at me with a
257+
// heap buffer overflow whenever I try a query that references the same non-null attribute multiple
258+
// times (e.g. 'SELECT id FROM t WHERE id < 3 AND id > 1'). Leaving it commented out prevents the
259+
// memory error, but then this prevents the is_not_null flag of a tuple expression from being
260+
// populated in some cases (specifically, when the expression's table name is initially empty).
261+
262+
//if (table_obj == nullptr) {
263+
// LOG_DEBUG("Extracting regular table object");
264+
// BinderContext::GetRegularTableObj(context_, table_name, table_obj, depth);
265+
//}
266+
267+
if (table_obj != nullptr) {
268+
expr->SetIsNotNull(table_obj->GetColumnCatalogEntry(std::get<2>(col_pos_tuple), false)->IsNotNull());
269+
}
253270
}
254271
}
255272

Diff for: src/include/common/internal_types.h

+8
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,14 @@ enum class RuleType : uint32_t {
13931393
TV_EQUALITY_WITH_TWO_CV, // (A.B = x) AND (A.B = y) where x/y are constant
13941394
TRANSITIVE_CLOSURE_CONSTANT, // (A.B = x) AND (A.B = C.D)
13951395

1396+
// Boolean short-circuit rules
1397+
AND_SHORT_CIRCUIT, // (FALSE AND B)
1398+
OR_SHORT_CIRCUIT, // (TRUE OR B)
1399+
1400+
// Catalog-based NULL/NON-NULL rules
1401+
NULL_LOOKUP_ON_NOT_NULL_COLUMN,
1402+
NOT_NULL_LOOKUP_ON_NOT_NULL_COLUMN,
1403+
13961404
// Place holder to generate number of rules compile time
13971405
NUM_RULES
13981406

Diff for: src/include/expression/tuple_value_expression.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class TupleValueExpression : public AbstractExpression {
7979
tuple_idx_ = tuple_idx;
8080
}
8181

82+
inline void SetIsNotNull(bool is_not_null) {
83+
is_not_null_ = is_not_null;
84+
}
85+
8286
/**
8387
* @brief Attribute binding
8488
* @param binding_contexts
@@ -116,6 +120,8 @@ class TupleValueExpression : public AbstractExpression {
116120
if ((table_name_.empty() xor other.table_name_.empty()) ||
117121
col_name_.empty() xor other.col_name_.empty())
118122
return false;
123+
if (GetIsNotNull() != other.GetIsNotNull())
124+
return false;
119125
bool res = bound_obj_id_ == other.bound_obj_id_;
120126
if (!table_name_.empty() && !other.table_name_.empty())
121127
res = table_name_ == other.table_name_ && res;
@@ -151,6 +157,8 @@ class TupleValueExpression : public AbstractExpression {
151157

152158
bool GetIsBound() const { return is_bound_; }
153159

160+
bool GetIsNotNull() const { return is_not_null_; }
161+
154162
const std::tuple<oid_t, oid_t, oid_t> &GetBoundOid() const {
155163
return bound_obj_id_;
156164
}
@@ -185,7 +193,8 @@ class TupleValueExpression : public AbstractExpression {
185193
value_idx_(other.value_idx_),
186194
tuple_idx_(other.tuple_idx_),
187195
table_name_(other.table_name_),
188-
col_name_(other.col_name_) {}
196+
col_name_(other.col_name_),
197+
is_not_null_(other.is_not_null_) {}
189198

190199
// Bound flag
191200
bool is_bound_ = false;
@@ -196,6 +205,7 @@ class TupleValueExpression : public AbstractExpression {
196205
int tuple_idx_;
197206
std::string table_name_;
198207
std::string col_name_;
208+
bool is_not_null_ = false;
199209

200210
const planner::AttributeInfo *ai_;
201211
};

Diff for: src/include/optimizer/rule_rewrite.h

+45
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,50 @@ class TransitiveClosureConstantTransform: public Rule<AbsExpr_Container,Expressi
7474
OptimizeContextTemplate *context) const override;
7575
};
7676

77+
class AndShortCircuit: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
78+
public:
79+
AndShortCircuit();
80+
81+
int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
82+
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
83+
void Transform(std::shared_ptr<AbsExpr_Expression> input,
84+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
85+
OptimizeContextTemplate *context) const override;
86+
};
87+
88+
class OrShortCircuit: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
89+
public:
90+
OrShortCircuit();
91+
92+
int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
93+
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
94+
void Transform(std::shared_ptr<AbsExpr_Expression> input,
95+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
96+
OptimizeContextTemplate *context) const override;
97+
};
98+
99+
class NullLookupOnNotNullColumn: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
100+
public:
101+
NullLookupOnNotNullColumn();
102+
103+
int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
104+
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
105+
void Transform(std::shared_ptr<AbsExpr_Expression> input,
106+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
107+
OptimizeContextTemplate *context) const override;
108+
};
109+
110+
class NotNullLookupOnNotNullColumn: public Rule<AbsExpr_Container,ExpressionType,AbsExpr_Expression> {
111+
public:
112+
NotNullLookupOnNotNullColumn();
113+
114+
int Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const override;
115+
bool Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const override;
116+
void Transform(std::shared_ptr<AbsExpr_Expression> input,
117+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
118+
OptimizeContextTemplate *context) const override;
119+
};
120+
121+
77122
} // namespace optimizer
78123
} // namespace peloton

Diff for: src/optimizer/binding.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212

1313
#include "optimizer/binding.h"
1414

15+
#include <memory>
16+
1517
#include "common/logger.h"
1618
#include "optimizer/operator_visitor.h"
1719
#include "optimizer/optimizer.h"
1820
#include "optimizer/absexpr_expression.h"
1921
#include "expression/group_marker_expression.h"
22+
#include "expression/abstract_expression.h"
23+
#include "expression/tuple_value_expression.h"
2024

2125
namespace peloton {
2226
namespace optimizer {
@@ -134,6 +138,7 @@ GroupExprBindingIterator<Node,OperatorType,OperatorExpr>::GroupExprBindingIterat
134138
first_(true),
135139
has_next_(false),
136140
current_binding_(std::make_shared<OperatorExpr>(gexpr->Op())) {
141+
// First check to make sure that types of pattern & expression match
137142
if (gexpr->Op().GetType() != pattern->Type()) {
138143
return;
139144
}

Diff for: src/optimizer/rule.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ RuleSet<AbsExpr_Container,ExpressionType,AbsExpr_Expression>::RuleSet() {
8888
// Additional rules
8989
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new TVEqualityWithTwoCVTransform());
9090
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new TransitiveClosureConstantTransform());
91+
92+
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new AndShortCircuit());
93+
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new OrShortCircuit());
94+
95+
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new NullLookupOnNotNullColumn());
96+
AddRewriteRule(RewriteRuleSetName::GENERIC_RULES, new NotNullLookupOnNotNullColumn());
9197
}
9298

9399
template <>

Diff for: src/optimizer/rule_rewrite.cpp

+208
Original file line numberDiff line numberDiff line change
@@ -397,5 +397,213 @@ void TransitiveClosureConstantTransform::Transform(std::shared_ptr<AbsExpr_Expre
397397
transformed.push_back(abs_expr);
398398
}
399399

400+
// ===========================================================
401+
//
402+
// Boolean short-circuit related functions
403+
//
404+
// ===========================================================
405+
AndShortCircuit::AndShortCircuit() {
406+
type_ = RuleType::AND_SHORT_CIRCUIT;
407+
408+
// (FALSE AND <any expression>)
409+
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::CONJUNCTION_AND);
410+
auto left_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_CONSTANT);
411+
auto right_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::GROUP_MARKER);
412+
413+
match_pattern->AddChild(left_child);
414+
match_pattern->AddChild(right_child);
415+
}
416+
417+
int AndShortCircuit::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
418+
(void)group_expr;
419+
(void)context;
420+
return static_cast<int>(RulePriority::HIGH);
421+
}
422+
423+
bool AndShortCircuit::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
424+
(void)plan;
425+
(void)context;
426+
return true;
427+
}
428+
429+
void AndShortCircuit::Transform(std::shared_ptr<AbsExpr_Expression> input,
430+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
431+
OptimizeContextTemplate *context) const {
432+
(void)context;
433+
(void)transformed;
434+
435+
// Asserting guarantees provided by the GroupExprBindingIterator
436+
// Structure: (FALSE AND <any expression>)
437+
PELOTON_ASSERT(input->Children().size() == 2);
438+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_AND);
439+
440+
std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
441+
PELOTON_ASSERT(left->Children().size() == 0);
442+
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);
443+
444+
std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
445+
type::Value left_value = left_cv_expr->GetValue();
446+
447+
// Only transform the expression if we're ANDing a FALSE boolean value
448+
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsFalse()) {
449+
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
450+
std::shared_ptr<expression::ConstantValueExpression> false_expr = std::make_shared<expression::ConstantValueExpression>(val_false);
451+
std::shared_ptr<AbsExpr_Expression> false_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(false_expr));
452+
transformed.push_back(false_container);
453+
}
454+
}
455+
456+
457+
OrShortCircuit::OrShortCircuit() {
458+
type_ = RuleType::OR_SHORT_CIRCUIT;
459+
460+
// (FALSE AND <any expression>)
461+
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::CONJUNCTION_OR);
462+
auto left_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_CONSTANT);
463+
auto right_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::GROUP_MARKER);
464+
465+
match_pattern->AddChild(left_child);
466+
match_pattern->AddChild(right_child);
467+
}
468+
469+
int OrShortCircuit::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
470+
(void)group_expr;
471+
(void)context;
472+
return static_cast<int>(RulePriority::HIGH);
473+
}
474+
475+
bool OrShortCircuit::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
476+
(void)plan;
477+
(void)context;
478+
return true;
479+
}
480+
481+
void OrShortCircuit::Transform(std::shared_ptr<AbsExpr_Expression> input,
482+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
483+
OptimizeContextTemplate *context) const {
484+
(void)context;
485+
(void)transformed;
486+
487+
// Asserting guarantees provided by the GroupExprBindingIterator
488+
// Structure: (TRUE OR <any expression>)
489+
PELOTON_ASSERT(input->Children().size() == 2);
490+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_OR);
491+
492+
std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
493+
PELOTON_ASSERT(left->Children().size() == 0);
494+
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);
495+
496+
std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
497+
type::Value left_value = left_cv_expr->GetValue();
498+
499+
// Only transform the expression if we're ANDing a TRUE boolean value
500+
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsTrue()) {
501+
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
502+
std::shared_ptr<expression::ConstantValueExpression> true_expr = std::make_shared<expression::ConstantValueExpression>(val_true);
503+
std::shared_ptr<AbsExpr_Expression> true_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(true_expr));
504+
transformed.push_back(true_container);
505+
}
506+
}
507+
508+
509+
NullLookupOnNotNullColumn::NullLookupOnNotNullColumn() {
510+
type_ = RuleType::NULL_LOOKUP_ON_NOT_NULL_COLUMN;
511+
512+
// Structure: [T.X IS NULL]
513+
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::OPERATOR_IS_NULL);
514+
auto child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_TUPLE);
515+
516+
match_pattern->AddChild(child);
517+
}
518+
519+
int NullLookupOnNotNullColumn::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
520+
(void)group_expr;
521+
(void)context;
522+
return static_cast<int>(RulePriority::HIGH);
523+
}
524+
525+
bool NullLookupOnNotNullColumn::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
526+
(void)plan;
527+
(void)context;
528+
return true;
529+
}
530+
531+
void NullLookupOnNotNullColumn::Transform(std::shared_ptr<AbsExpr_Expression> input,
532+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
533+
OptimizeContextTemplate *context) const {
534+
(void)context;
535+
(void)transformed;
536+
537+
// Asserting guarantees provided by the GroupExprBindingIterator
538+
// Structure: (TRUE OR <any expression>)
539+
PELOTON_ASSERT(input->Children().size() == 1);
540+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::OPERATOR_IS_NULL);
541+
542+
std::shared_ptr<AbsExpr_Expression> child = input->Children()[0];
543+
PELOTON_ASSERT(child->Children().size() == 0);
544+
PELOTON_ASSERT(child->Op().GetType() == ExpressionType::VALUE_TUPLE);
545+
546+
std::shared_ptr<expression::TupleValueExpression> tuple_expr = std::dynamic_pointer_cast<expression::TupleValueExpression>(child->Op().GetExpr());
547+
548+
// Only transform into [FALSE] if the tuple value expression is specifically non-NULL,
549+
// otherwise do nothing
550+
if (tuple_expr->GetIsNotNull()) {
551+
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
552+
std::shared_ptr<expression::ConstantValueExpression> false_expr = std::make_shared<expression::ConstantValueExpression>(val_false);
553+
std::shared_ptr<AbsExpr_Expression> false_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(false_expr));
554+
transformed.push_back(false_container);
555+
}
556+
}
557+
558+
559+
NotNullLookupOnNotNullColumn::NotNullLookupOnNotNullColumn() {
560+
type_ = RuleType::NOT_NULL_LOOKUP_ON_NOT_NULL_COLUMN;
561+
562+
// Structure: [T.X IS NOT NULL]
563+
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::OPERATOR_IS_NOT_NULL);
564+
auto child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_TUPLE);
565+
566+
match_pattern->AddChild(child);
567+
}
568+
569+
int NotNullLookupOnNotNullColumn::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
570+
(void)group_expr;
571+
(void)context;
572+
return static_cast<int>(RulePriority::HIGH);
573+
}
574+
575+
bool NotNullLookupOnNotNullColumn::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
576+
(void)plan;
577+
(void)context;
578+
return true;
579+
}
580+
581+
void NotNullLookupOnNotNullColumn::Transform(std::shared_ptr<AbsExpr_Expression> input,
582+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
583+
OptimizeContextTemplate *context) const {
584+
(void)context;
585+
(void)transformed;
586+
587+
// Asserting guarantees provided by the GroupExprBindingIterator
588+
// Structure: (TRUE OR <any expression>)
589+
PELOTON_ASSERT(input->Children().size() == 1);
590+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::OPERATOR_IS_NOT_NULL);
591+
592+
std::shared_ptr<AbsExpr_Expression> child = input->Children()[0];
593+
PELOTON_ASSERT(child->Children().size() == 0);
594+
PELOTON_ASSERT(child->Op().GetType() == ExpressionType::VALUE_TUPLE);
595+
596+
std::shared_ptr<expression::TupleValueExpression> tuple_expr = std::dynamic_pointer_cast<expression::TupleValueExpression>(child->Op().GetExpr());
597+
598+
// Only transform into [TRUE] if the tuple value expression is specifically non-NULL,
599+
// otherwise do nothing
600+
if (tuple_expr->GetIsNotNull()) {
601+
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
602+
std::shared_ptr<expression::ConstantValueExpression> true_expr = std::make_shared<expression::ConstantValueExpression>(val_true);
603+
std::shared_ptr<AbsExpr_Expression> true_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(true_expr));
604+
transformed.push_back(true_container);
605+
}
606+
}
607+
400608
} // namespace optimizer
401609
} // namespace peloton

0 commit comments

Comments
 (0)