diff --git a/go/vt/vtgate/planbuilder/dptable.go b/go/vt/vtgate/planbuilder/dptable.go new file mode 100644 index 00000000000..c65870cddc2 --- /dev/null +++ b/go/vt/vtgate/planbuilder/dptable.go @@ -0,0 +1,59 @@ +/* +Copyright 2020 The Vitess Authors. + +Licensed 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. +*/ + +package planbuilder + +import "vitess.io/vitess/go/vt/vtgate/semantics" + +// dpTable, is the hashmap we store results in during +// the dynamic programming part of query planning +type dpTable struct { + // hash map of the best solution for each seen table + m map[semantics.TableSet]joinTree + + highest semantics.TableSet +} + +func makeDPTable() *dpTable { + return &dpTable{ + m: map[semantics.TableSet]joinTree{}, + } +} + +func (dpt *dpTable) add(tree joinTree) { + solved := tree.solves() + if dpt.highest < solved { + dpt.highest = solved + } + dpt.m[solved] = tree +} + +func (dpt *dpTable) planFor(id semantics.TableSet) joinTree { + return dpt.m[id] +} + +func (dpt *dpTable) bitSetsOfSize(wanted int) []joinTree { + var result []joinTree + for x := semantics.TableSet(1); x <= dpt.highest; x++ { + if x.NumberOfTables() == wanted { + t, ok := dpt.m[x] + if ok { + result = append(result, t) + } + } + } + return result +} diff --git a/go/vt/vtgate/planbuilder/dptable_test.go b/go/vt/vtgate/planbuilder/dptable_test.go new file mode 100644 index 00000000000..e0e10e1b153 --- /dev/null +++ b/go/vt/vtgate/planbuilder/dptable_test.go @@ -0,0 +1,63 @@ +/* +Copyright 2020 The Vitess Authors. + +Licensed 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. +*/ + +package planbuilder + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "vitess.io/vitess/go/vt/vtgate/semantics" +) + +type fakePlan struct { + solve semantics.TableSet +} + +func (f *fakePlan) solves() semantics.TableSet { + return f.solve +} + +func (f *fakePlan) cost() int { + return 1 +} + +var _ joinTree = (*fakePlan)(nil) + +func TestDpTableSizeOf(t *testing.T) { + dpTable := makeDPTable() + + a := semantics.TableSet(1) + b := semantics.TableSet(2) + + t1 := &fakePlan{solve: a} + t2 := &fakePlan{solve: b} + t3 := &fakePlan{solve: a.Merge(b)} + + dpTable.add(t1) + dpTable.add(t2) + dpTable.add(t3) + + size1 := dpTable.bitSetsOfSize(1) + assert.Equal(t, []joinTree{t1, t2}, size1, "size 1") + + size2 := dpTable.bitSetsOfSize(2) + assert.Equal(t, []joinTree{t3}, size2, "size 2") + assert.Equal(t, t1, dpTable.planFor(a)) + assert.Equal(t, t2, dpTable.planFor(b)) + assert.Equal(t, t3, dpTable.planFor(a.Merge(b))) +} diff --git a/go/vt/vtgate/planbuilder/route_planning.go b/go/vt/vtgate/planbuilder/route_planning.go index 9dc37fc283d..60144023284 100644 --- a/go/vt/vtgate/planbuilder/route_planning.go +++ b/go/vt/vtgate/planbuilder/route_planning.go @@ -112,45 +112,8 @@ type ( lhs, rhs joinTree } - dpTableT struct { - // hash map of the best solution for each seen table - m map[semantics.TableSet]joinTree - - highest semantics.TableSet - } ) -func makeDPTable() *dpTableT { - return &dpTableT{ - m: map[semantics.TableSet]joinTree{}, - } -} - -func (dpt *dpTableT) add(tree joinTree) { - solved := tree.solves() - if dpt.highest < solved { - dpt.highest = solved - } - dpt.m[solved] = tree -} - -func (dpt *dpTableT) planFor(id semantics.TableSet) joinTree { - return dpt.m[id] -} - -func (dpt *dpTableT) bitSetsOfSize(wanted int) []joinTree { - var result []joinTree - for x := semantics.TableSet(1); x < dpt.highest; x++ { - if x.NumberOfTables() == wanted { - t, ok := dpt.m[x] - if ok { - result = append(result, t) - } - } - } - return result -} - func (rp *routePlan) solves() semantics.TableSet { return rp.solved } diff --git a/go/vt/vtgate/planbuilder/testdata/onecase.txt b/go/vt/vtgate/planbuilder/testdata/onecase.txt index e819513f354..0ce1a45f0c9 100644 --- a/go/vt/vtgate/planbuilder/testdata/onecase.txt +++ b/go/vt/vtgate/planbuilder/testdata/onecase.txt @@ -1 +1,39 @@ # Add your test case here for debugging and run go test -run=One. +# ',' join +"select music.col from user, music" +{ + "QueryType": "SELECT", + "Original": "select music.col from user, music", + "Instructions": { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "1", + "TableName": "user_music", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "SelectScatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select 1 from user where 1 != 1", + "Query": "select 1 from user", + "Table": "user" + }, + { + "OperatorType": "Route", + "Variant": "SelectScatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select music.col from music where 1 != 1", + "Query": "select music.col from music", + "Table": "music" + } + ] + } +} +{ +}