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

Commit 1648780

Browse files
author
Erik Sargent
committed
Short circuit rules
1 parent b5d020c commit 1648780

File tree

6 files changed

+265
-1
lines changed

6 files changed

+265
-1
lines changed

src/include/common/internal_types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,10 @@ enum class RuleType : uint32_t {
13931393
TRANSITIVE_SINGLE_DEPTH, // (A.B = x) AND (A.B = y)
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+
13961400
// Place holder to generate number of rules compile time
13971401
NUM_RULES
13981402

src/include/optimizer/rule.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ enum class RewriteRuleSetName : uint32_t {
116116
UNNEST_SUBQUERY,
117117
COMPARATOR_ELIMINATION,
118118
EQUIVALENT_TRANSFORM,
119-
TRANSITIVE_TRANSFORM
119+
TRANSITIVE_TRANSFORM,
120+
BOOLEAN_SHORT_CIRCUIT
120121
};
121122

122123
/**

src/include/optimizer/rule_rewrite.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,27 @@ 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+
7799
} // namespace optimizer
78100
} // namespace peloton

src/optimizer/rule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ RuleSet<AbsExpr_Container,ExpressionType,AbsExpr_Expression>::RuleSet() {
8383

8484
AddRewriteRule(RewriteRuleSetName::TRANSITIVE_TRANSFORM, new TransitiveSingleDepthTransform());
8585
AddRewriteRule(RewriteRuleSetName::TRANSITIVE_TRANSFORM, new TransitiveClosureConstantTransform());
86+
87+
AddRewriteRule(RewriteRuleSetName::BOOLEAN_SHORT_CIRCUIT, new AndShortCircuit());
88+
AddRewriteRule(RewriteRuleSetName::BOOLEAN_SHORT_CIRCUIT, new OrShortCircuit());
8689
}
8790

8891
template <>

src/optimizer/rule_rewrite.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,5 +397,118 @@ 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+
LOG_DEBUG("Transforming AND!");
436+
437+
// Asserting guarantees provided by the GroupExprBindingIterator
438+
// Structure: (FALSE AND <any expression>)
439+
PELOTON_ASSERT(input->Children().size() == 2);
440+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_AND);
441+
442+
std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
443+
PELOTON_ASSERT(left->Children().size() == 0);
444+
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);
445+
446+
std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
447+
type::Value left_value = left_cv_expr->GetValue();
448+
449+
// Only transform the expression if we're ANDing a FALSE boolean value
450+
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsFalse()) {
451+
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
452+
std::shared_ptr<expression::ConstantValueExpression> false_expr = std::make_shared<expression::ConstantValueExpression>(val_false);
453+
std::shared_ptr<AbsExpr_Expression> false_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(false_expr));
454+
transformed.push_back(false_container);
455+
}
456+
}
457+
458+
459+
OrShortCircuit::OrShortCircuit() {
460+
type_ = RuleType::OR_SHORT_CIRCUIT;
461+
462+
// (FALSE AND <any expression>)
463+
match_pattern = std::make_shared<Pattern<ExpressionType>>(ExpressionType::CONJUNCTION_OR);
464+
auto left_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::VALUE_CONSTANT);
465+
auto right_child = std::make_shared<Pattern<ExpressionType>>(ExpressionType::GROUP_MARKER);
466+
467+
match_pattern->AddChild(left_child);
468+
match_pattern->AddChild(right_child);
469+
}
470+
471+
int OrShortCircuit::Promise(GroupExprTemplate *group_expr, OptimizeContextTemplate *context) const {
472+
(void)group_expr;
473+
(void)context;
474+
return static_cast<int>(RulePriority::HIGH);
475+
}
476+
477+
bool OrShortCircuit::Check(std::shared_ptr<AbsExpr_Expression> plan, OptimizeContextTemplate *context) const {
478+
(void)plan;
479+
(void)context;
480+
return true;
481+
}
482+
483+
void OrShortCircuit::Transform(std::shared_ptr<AbsExpr_Expression> input,
484+
std::vector<std::shared_ptr<AbsExpr_Expression>> &transformed,
485+
OptimizeContextTemplate *context) const {
486+
(void)context;
487+
(void)transformed;
488+
489+
LOG_DEBUG("Transforming OR!");
490+
491+
// Asserting guarantees provided by the GroupExprBindingIterator
492+
// Structure: (TRUE OR <any expression>)
493+
PELOTON_ASSERT(input->Children().size() == 2);
494+
PELOTON_ASSERT(input->Op().GetType() == ExpressionType::CONJUNCTION_OR);
495+
496+
std::shared_ptr<AbsExpr_Expression> left = input->Children()[0];
497+
PELOTON_ASSERT(left->Children().size() == 0);
498+
PELOTON_ASSERT(left->Op().GetType() == ExpressionType::VALUE_CONSTANT);
499+
500+
std::shared_ptr<expression::ConstantValueExpression> left_cv_expr = std::dynamic_pointer_cast<expression::ConstantValueExpression>(left->Op().GetExpr());
501+
type::Value left_value = left_cv_expr->GetValue();
502+
503+
// Only transform the expression if we're ANDing a TRUE boolean value
504+
if (left_value.GetTypeId() == type::TypeId::BOOLEAN && left_value.IsTrue()) {
505+
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
506+
std::shared_ptr<expression::ConstantValueExpression> true_expr = std::make_shared<expression::ConstantValueExpression>(val_true);
507+
std::shared_ptr<AbsExpr_Expression> true_container = std::make_shared<AbsExpr_Expression>(AbsExpr_Container(true_expr));
508+
transformed.push_back(true_container);
509+
}
510+
}
511+
512+
400513
} // namespace optimizer
401514
} // namespace peloton

test/optimizer/rewriter_test.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,126 @@ TEST_F(RewriterTests, ComparativeOperatorTest) {
142142
delete rewrote;
143143
}
144144

145+
TEST_F(RewriterTests, BasicAndShortCircuitTest) {
146+
147+
// First, build the rewriter and the values that will be used in test cases
148+
Rewriter *rewriter = new Rewriter();
149+
150+
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
151+
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
152+
type::Value val3 = type::ValueFactory::GetIntegerValue(3);
153+
154+
//
155+
// [AND]
156+
// [FALSE] [=]
157+
// [X] [3]
158+
//
159+
// Intended output: [FALSE]
160+
//
161+
162+
expression::ConstantValueExpression *lh = new expression::ConstantValueExpression(val_false);
163+
expression::ConstantValueExpression *rh_right_child = new expression::ConstantValueExpression(val3);
164+
expression::TupleValueExpression *rh_left_child = new expression::TupleValueExpression("t","x");
165+
166+
expression::ComparisonExpression *rh = new expression::ComparisonExpression(ExpressionType::COMPARE_EQUAL, rh_left_child, rh_right_child);
167+
expression::ConjunctionExpression *root = new expression::ConjunctionExpression(ExpressionType::CONJUNCTION_AND, lh, rh);
168+
169+
expression::AbstractExpression *rewrote = rewriter->RewriteExpression(root);
170+
171+
EXPECT_TRUE(rewrote != nullptr);
172+
EXPECT_EQ(rewrote->GetChildrenSize(), 0);
173+
EXPECT_EQ(rewrote->GetExpressionType(), ExpressionType::VALUE_CONSTANT);
174+
175+
delete rewrote;
176+
delete root;
177+
178+
//
179+
// [AND]
180+
// [TRUE] [=]
181+
// [X] [3]
182+
//
183+
// Intended output: same as input
184+
//
185+
186+
lh = new expression::ConstantValueExpression(val_true);
187+
rh_right_child = new expression::ConstantValueExpression(val3);
188+
rh_left_child = new expression::TupleValueExpression("t","x");
189+
190+
rh = new expression::ComparisonExpression(ExpressionType::COMPARE_EQUAL, rh_left_child, rh_right_child);
191+
root = new expression::ConjunctionExpression(ExpressionType::CONJUNCTION_AND, lh, rh);
192+
193+
rewrote = rewriter->RewriteExpression(root);
194+
195+
EXPECT_TRUE(rewrote != nullptr);
196+
EXPECT_EQ(rewrote->GetChildrenSize(), 2);
197+
EXPECT_EQ(rewrote->GetExpressionType(), ExpressionType::CONJUNCTION_AND);
198+
199+
delete rewrote;
200+
delete root;
201+
202+
delete rewriter;
203+
}
204+
205+
206+
TEST_F(RewriterTests, BasicOrShortCircuitTest) {
207+
// First, build the rewriter and the values that will be used in test cases
208+
Rewriter *rewriter = new Rewriter();
209+
210+
type::Value val_false = type::ValueFactory::GetBooleanValue(false);
211+
type::Value val_true = type::ValueFactory::GetBooleanValue(true);
212+
type::Value val3 = type::ValueFactory::GetIntegerValue(3);
213+
214+
//
215+
// [OR]
216+
// [TRUE] [=]
217+
// [X] [3]
218+
//
219+
// Intended output: [TRUE]
220+
//
221+
222+
expression::ConstantValueExpression *lh = new expression::ConstantValueExpression(val_true);
223+
expression::ConstantValueExpression *rh_right_child = new expression::ConstantValueExpression(val3);
224+
expression::TupleValueExpression *rh_left_child = new expression::TupleValueExpression("t","x");
225+
226+
expression::ComparisonExpression *rh = new expression::ComparisonExpression(ExpressionType::COMPARE_EQUAL, rh_left_child, rh_right_child);
227+
expression::ConjunctionExpression *root = new expression::ConjunctionExpression(ExpressionType::CONJUNCTION_OR, lh, rh);
228+
229+
expression::AbstractExpression *rewrote = rewriter->RewriteExpression(root);
230+
231+
EXPECT_TRUE(rewrote != nullptr);
232+
EXPECT_EQ(rewrote->GetChildrenSize(), 0);
233+
EXPECT_EQ(rewrote->GetExpressionType(), ExpressionType::VALUE_CONSTANT);
234+
235+
delete rewrote;
236+
delete root;
237+
238+
//
239+
// [OR]
240+
// [FALSE] [=]
241+
// [X] [3]
242+
//
243+
// Intended output: same as input
244+
//
245+
246+
lh = new expression::ConstantValueExpression(val_false);
247+
rh_right_child = new expression::ConstantValueExpression(val3);
248+
rh_left_child = new expression::TupleValueExpression("t","x");
249+
250+
rh = new expression::ComparisonExpression(ExpressionType::COMPARE_EQUAL, rh_left_child, rh_right_child);
251+
root = new expression::ConjunctionExpression(ExpressionType::CONJUNCTION_OR, lh, rh);
252+
253+
rewrote = rewriter->RewriteExpression(root);
254+
255+
EXPECT_TRUE(rewrote != nullptr);
256+
EXPECT_EQ(rewrote->GetChildrenSize(), 2);
257+
EXPECT_EQ(rewrote->GetExpressionType(), ExpressionType::CONJUNCTION_OR);
258+
259+
delete rewrote;
260+
delete root;
261+
262+
delete rewriter;
263+
}
264+
265+
145266
} // namespace test
146267
} // namespace peloton

0 commit comments

Comments
 (0)