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

Commit 3b64df8

Browse files
authored
Merge pull request #1242 from chenboy/join_order_fix
Fix 4 table join bug in binding iterator
2 parents 5b16e38 + e5360ae commit 3b64df8

File tree

7 files changed

+89
-33
lines changed

7 files changed

+89
-33
lines changed

src/include/optimizer/operator_expression.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class OperatorExpression {
3535

3636
const Operator &Op() const;
3737

38+
const std::string GetInfo() const;
39+
3840
private:
3941
Operator op;
4042
std::vector<std::shared_ptr<OperatorExpression>> children;

src/optimizer/binding.cpp

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@
1919
namespace peloton {
2020
namespace optimizer {
2121

22-
2322
//===--------------------------------------------------------------------===//
2423
// Group Binding Iterator
2524
//===--------------------------------------------------------------------===//
26-
GroupBindingIterator::GroupBindingIterator(Memo& memo, GroupID id,
25+
GroupBindingIterator::GroupBindingIterator(Memo &memo, GroupID id,
2726
std::shared_ptr<Pattern> pattern)
2827
: BindingIterator(memo),
2928
group_id_(id),
@@ -52,7 +51,8 @@ bool GroupBindingIterator::HasNext() {
5251
// Keep checking item iterators until we find a match
5352
while (current_item_index_ < num_group_items_) {
5453
current_iterator_.reset(new GroupExprBindingIterator(
55-
memo_, target_group_->GetLogicalExpressions()[current_item_index_].get(),
54+
memo_,
55+
target_group_->GetLogicalExpressions()[current_item_index_].get(),
5656
pattern_));
5757

5858
if (current_iterator_->HasNext()) {
@@ -78,24 +78,29 @@ std::shared_ptr<OperatorExpression> GroupBindingIterator::Next() {
7878
//===--------------------------------------------------------------------===//
7979
// Item Binding Iterator
8080
//===--------------------------------------------------------------------===//
81-
GroupExprBindingIterator::GroupExprBindingIterator(Memo& memo,
82-
GroupExpression *gexpr,
83-
std::shared_ptr<Pattern> pattern)
81+
GroupExprBindingIterator::GroupExprBindingIterator(
82+
Memo &memo, GroupExpression *gexpr, std::shared_ptr<Pattern> pattern)
8483
: BindingIterator(memo),
8584
gexpr_(gexpr),
8685
pattern_(pattern),
8786
first_(true),
8887
has_next_(false),
8988
current_binding_(std::make_shared<OperatorExpression>(gexpr->Op())) {
90-
LOG_TRACE("Attempting to bind on group %d with expression of type %s",
91-
gexpr->GetGroupID(), gexpr->Op().GetName().c_str());
92-
if (gexpr->Op().GetType() != pattern->Type()) return;
89+
if (gexpr->Op().GetType() != pattern->Type()) {
90+
return;
91+
}
9392

9493
const std::vector<GroupID> &child_groups = gexpr->GetChildGroupIDs();
9594
const std::vector<std::shared_ptr<Pattern>> &child_patterns =
9695
pattern->Children();
9796

98-
if (child_groups.size() != child_patterns.size()) return;
97+
if (child_groups.size() != child_patterns.size()) {
98+
return;
99+
}
100+
LOG_TRACE(
101+
"Attempting to bind on group %d with expression of type %s, children "
102+
"size %lu",
103+
gexpr->GetGroupID(), gexpr->Op().GetName().c_str(), child_groups.size());
99104

100105
// Find all bindings for children
101106
children_bindings_.resize(child_groups.size(), {});
@@ -104,15 +109,16 @@ GroupExprBindingIterator::GroupExprBindingIterator(Memo& memo,
104109
// Try to find a match in the given group
105110
std::vector<std::shared_ptr<OperatorExpression>> &child_bindings =
106111
children_bindings_[i];
107-
GroupBindingIterator iterator(memo_, child_groups[i],
108-
child_patterns[i]);
112+
GroupBindingIterator iterator(memo_, child_groups[i], child_patterns[i]);
109113

110114
// Get all bindings
111115
while (iterator.HasNext()) {
112116
child_bindings.push_back(iterator.Next());
113117
}
114118

115-
if (child_bindings.size() == 0) return;
119+
if (child_bindings.size() == 0) {
120+
return;
121+
}
116122

117123
current_binding_->PushChild(child_bindings[0]);
118124
}
@@ -128,33 +134,37 @@ bool GroupExprBindingIterator::HasNext() {
128134
}
129135

130136
if (has_next_) {
131-
size_t size = children_bindings_pos_.size();
132-
size_t i;
133-
for (i = 0; i < size; ++i) {
137+
// The first child to be modified
138+
int first_modified_idx = children_bindings_pos_.size() - 1;
139+
for (; first_modified_idx >= 0; --first_modified_idx) {
134140
const std::vector<std::shared_ptr<OperatorExpression>> &child_binding =
135-
children_bindings_[size - 1 - i];
141+
children_bindings_[first_modified_idx];
136142

137-
size_t new_pos = ++children_bindings_pos_[size - 1 - i];
143+
// Try to increment idx from the back
144+
size_t new_pos = ++children_bindings_pos_[first_modified_idx];
138145
if (new_pos < child_binding.size()) {
139146
break;
140147
} else {
141-
children_bindings_pos_[size - 1 - i] = 0;
148+
children_bindings_pos_[first_modified_idx] = 0;
142149
}
143150
}
144151

145-
if (i == size) {
152+
if (first_modified_idx < 0) {
146153
// We have explored all combinations of the child bindings
147154
has_next_ = false;
148155
} else {
149-
for (size_t j = 0; j<i; j++)
156+
// Pop all updated childrens
157+
for (size_t idx = first_modified_idx; idx < children_bindings_pos_.size();
158+
idx++) {
150159
current_binding_->PopChild();
151-
// Replay to end
152-
size_t offset = size - 1 - i;
153-
for (size_t j = 0; j < i + 1; ++j) {
160+
}
161+
// Add new children to end
162+
for (size_t offset = first_modified_idx;
163+
offset < children_bindings_pos_.size(); ++offset) {
154164
const std::vector<std::shared_ptr<OperatorExpression>> &child_binding =
155-
children_bindings_[offset + j];
165+
children_bindings_[offset];
156166
std::shared_ptr<OperatorExpression> binding =
157-
child_binding[children_bindings_pos_[offset + j]];
167+
child_binding[children_bindings_pos_[offset]];
158168
current_binding_->PushChild(binding);
159169
}
160170
}

src/optimizer/memo.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ GroupExpression *Memo::InsertExpression(std::shared_ptr<GroupExpression> gexpr,
3333
// If leaf, then just return
3434
if (gexpr->Op().GetType() == OpType::Leaf) {
3535
const LeafOperator *leaf = gexpr->Op().As<LeafOperator>();
36-
assert(target_group == UNDEFINED_GROUP ||
36+
PL_ASSERT(target_group == UNDEFINED_GROUP ||
3737
target_group == leaf->origin_group);
3838
gexpr->SetGroupID(leaf->origin_group);
3939
return nullptr;
@@ -43,7 +43,7 @@ GroupExpression *Memo::InsertExpression(std::shared_ptr<GroupExpression> gexpr,
4343
auto it = group_expressions_.find(gexpr.get());
4444

4545
if (it != group_expressions_.end()) {
46-
assert(target_group == UNDEFINED_GROUP ||
46+
PL_ASSERT(target_group == UNDEFINED_GROUP ||
4747
target_group == (*it)->GetGroupID());
4848
gexpr->SetGroupID((*it)->GetGroupID());
4949
return *it;

src/optimizer/operator_expression.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,37 @@ void OperatorExpression::PushChild(std::shared_ptr<OperatorExpression> op) {
2828

2929
void OperatorExpression::PopChild() { children.pop_back(); }
3030

31-
const std::vector<std::shared_ptr<OperatorExpression>> &
32-
OperatorExpression::Children() const {
31+
const std::vector<std::shared_ptr<OperatorExpression>>
32+
&OperatorExpression::Children() const {
3333
return children;
3434
}
3535

3636
const Operator &OperatorExpression::Op() const { return op; }
3737

38+
const std::string OperatorExpression::GetInfo() const {
39+
std::string info = "{";
40+
{
41+
info += "\"Op\":";
42+
info += "\"" + op.GetName() + "\",";
43+
if (!children.empty()) {
44+
info += "\"Children\":[";
45+
{
46+
bool is_first = true;
47+
for (const auto &child : children) {
48+
if (is_first == true) {
49+
is_first = false;
50+
} else {
51+
info += ",";
52+
}
53+
info += child->GetInfo();
54+
}
55+
}
56+
info += "]";
57+
}
58+
}
59+
info += '}';
60+
return info;
61+
}
62+
3863
} // namespace optimizer
3964
} // namespace peloton

src/optimizer/operators.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ Operator PhysicalSeqScan::make(
426426
oid_t get_id, std::shared_ptr<catalog::TableCatalogObject> table,
427427
std::string alias, std::vector<AnnotatedExpression> predicates,
428428
bool update) {
429-
assert(table != nullptr);
429+
PL_ASSERT(table != nullptr);
430430
PhysicalSeqScan *scan = new PhysicalSeqScan;
431431
scan->table_ = table;
432432
scan->table_alias = alias;
@@ -465,7 +465,7 @@ Operator PhysicalIndexScan::make(
465465
oid_t index_id, std::vector<oid_t> key_column_id_list,
466466
std::vector<ExpressionType> expr_type_list,
467467
std::vector<type::Value> value_list) {
468-
assert(table != nullptr);
468+
PL_ASSERT(table != nullptr);
469469
PhysicalIndexScan *scan = new PhysicalIndexScan;
470470
scan->table_ = table;
471471
scan->is_for_update = update;

src/optimizer/rule_impls.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void InnerJoinAssociativity::Transform(
109109
auto middle = children[0]->Children()[1];
110110
auto right = children[1];
111111

112-
LOG_TRACE("Reordered join structured: (%s JOIN %s) JOIN %s",
112+
LOG_DEBUG("Reordered join structured: (%s JOIN %s) JOIN %s",
113113
left->Op().GetName().c_str(), middle->Op().GetName().c_str(),
114114
right->Op().GetName().c_str());
115115

test/sql/optimizer_sql_test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ TEST_F(OptimizerSQLTests, SelectConstantTest) {
494494
}
495495

496496
TEST_F(OptimizerSQLTests, JoinTest) {
497+
// The original table
497498
// TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test VALUES (1, 22, 333);");
498499
// TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test VALUES (2, 11, 000);");
499500
// TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test VALUES (3, 33, 444);");
@@ -519,6 +520,16 @@ TEST_F(OptimizerSQLTests, JoinTest) {
519520
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test2 VALUES (3, 22, 555);");
520521
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test2 VALUES (4, 00, 000);");
521522

523+
// Create the fourth table
524+
TestingSQLUtil::ExecuteSQLQuery(
525+
"CREATE TABLE test3(a INT PRIMARY KEY, b INT, c INT);");
526+
527+
// Insert tuples into table
528+
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test3 VALUES (1, 22, 000);");
529+
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test3 VALUES (2, 11, 333);");
530+
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test3 VALUES (3, 22, 555);");
531+
TestingSQLUtil::ExecuteSQLQuery("INSERT INTO test3 VALUES (4, 00, 000);");
532+
522533
/************************* Basic Queries (only joins)
523534
* *******************************/
524535
// Product
@@ -637,6 +648,14 @@ TEST_F(OptimizerSQLTests, JoinTest) {
637648
"GROUP BY test.a "
638649
"ORDER BY test.a",
639650
{"22", "1", "11", "2", "22", "3", "0", "4"}, true);
651+
652+
// Basic 4 table join
653+
TestUtil(
654+
"SELECT test.a, test1.a, test2.a, test3.c FROM test, test1, test2, test3 "
655+
"WHERE test.a = test2.a AND test2.a = test1.a and test.b = test3.b",
656+
{"1", "1", "1", "0", "1", "1", "1", "555", "2", "2", "2", "333", "4",
657+
"4", "4", "0"},
658+
false);
640659
}
641660

642661
TEST_F(OptimizerSQLTests, IndexTest) {

0 commit comments

Comments
 (0)