From 24c359f0daf8aff25a25761570ad911ce15f9705 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Thu, 20 Feb 2025 15:50:55 +0100 Subject: [PATCH] wip --- go/vt/vtgate/planbuilder/operators/op_to_ast.go | 7 ++++++- go/vt/vtgate/planbuilder/operators/phases.go | 1 + .../planbuilder/operators/query_planning.go | 9 +++++++-- go/vt/vtgate/planbuilder/operators/values.go | 8 +++++++- .../vtgate/planbuilder/operators/values_join.go | 4 ++-- .../planbuilder/plancontext/planning_context.go | 9 +++++++++ go/vt/vtgate/planbuilder/testdata/onecase.json | 2 +- go/vt/vtgate/semantics/table_set.go | 17 +++++++++++++++++ 8 files changed, 50 insertions(+), 7 deletions(-) diff --git a/go/vt/vtgate/planbuilder/operators/op_to_ast.go b/go/vt/vtgate/planbuilder/operators/op_to_ast.go index 7e6f57b5954..050af192306 100644 --- a/go/vt/vtgate/planbuilder/operators/op_to_ast.go +++ b/go/vt/vtgate/planbuilder/operators/op_to_ast.go @@ -154,6 +154,7 @@ func buildValues(op *Values, qb *queryBuilder) { apa := semantics.EmptyTableSet() for _, ae := range qb.ctx.ValuesJoinColumns[op.Name] { apa = apa.Merge(qb.ctx.SemTable.RecursiveDeps(ae.Expr)) + fmt.Printf("%v\n", apa) } tableName := getTableName(qb.ctx, apa) @@ -165,18 +166,22 @@ func getTableName(ctx *plancontext.PlanningContext, id semantics.TableSet) strin var names []string for _, ts := range id.Constituents() { ti, err := ctx.SemTable.TableInfoFor(ts) + fmt.Printf("1: %v\n", ti) if err != nil { names = append(names, "X") continue } name, err := ti.Name() + fmt.Printf("2: %v\n", name) if err != nil { names = append(names, "X") continue } names = append(names, name.Name.String()) } - return strings.Join(names, "_") + x := strings.Join(names, "_") + fmt.Println("3: ", x) + return x } func buildDelete(op *Delete, qb *queryBuilder) { diff --git a/go/vt/vtgate/planbuilder/operators/phases.go b/go/vt/vtgate/planbuilder/operators/phases.go index bfb218342c5..bca7d4ebab0 100644 --- a/go/vt/vtgate/planbuilder/operators/phases.go +++ b/go/vt/vtgate/planbuilder/operators/phases.go @@ -157,6 +157,7 @@ func newValuesJoin(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinType v := &Values{ unaryOperator: newUnaryOp(rhs), Name: bindVariableName, + TableID: TableID(lhs), } return &ValuesJoin{ binaryOperator: newBinaryOp(lhs, v), diff --git a/go/vt/vtgate/planbuilder/operators/query_planning.go b/go/vt/vtgate/planbuilder/operators/query_planning.go index 4938f73e09a..ac041da5ce7 100644 --- a/go/vt/vtgate/planbuilder/operators/query_planning.go +++ b/go/vt/vtgate/planbuilder/operators/query_planning.go @@ -128,10 +128,15 @@ func runPushDownRewriters(ctx *plancontext.PlanningContext, root Operator) Opera func tryPushValues(ctx *plancontext.PlanningContext, in *Values) (Operator, *ApplyResult) { switch src := in.Source.(type) { + case *Values: + // we can merge two values operators into one + cols := ctx.ValuesJoinColumns[in.Name] + ctx.ValuesJoinColumns[src.Name] = append(ctx.ValuesJoinColumns[src.Name], cols...) + ctx.ValueJoins[in.Name] = ctx.ValueJoins[src.Name] + return src, Rewrote("merged two values operators") case *ValuesJoin: src.LHS = in.Clone([]Operator{src.LHS}) - src.RHS = in.Clone([]Operator{src.RHS}) - return src, Rewrote("pushed values under value join") + return src, Rewrote("pushed values to the LHS of values join") case *Filter: return Swap(in, src, "pushed values under filter") case *Route: diff --git a/go/vt/vtgate/planbuilder/operators/values.go b/go/vt/vtgate/planbuilder/operators/values.go index 1d803c14318..c8e25b27568 100644 --- a/go/vt/vtgate/planbuilder/operators/values.go +++ b/go/vt/vtgate/planbuilder/operators/values.go @@ -21,12 +21,14 @@ import ( "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" + "vitess.io/vitess/go/vt/vtgate/semantics" ) type Values struct { unaryOperator - Name string + Name string + TableID semantics.TableSet } func (v *Values) Clone(inputs []Operator) Operator { @@ -97,3 +99,7 @@ func (v *Values) ShortDescription() string { func (v *Values) GetOrdering(ctx *plancontext.PlanningContext) []OrderBy { return v.Source.GetOrdering(ctx) } + +func (v *Values) introducesTableID() semantics.TableSet { + return v.TableID +} diff --git a/go/vt/vtgate/planbuilder/operators/values_join.go b/go/vt/vtgate/planbuilder/operators/values_join.go index b9164c8d2ee..3fc27fbe3c4 100644 --- a/go/vt/vtgate/planbuilder/operators/values_join.go +++ b/go/vt/vtgate/planbuilder/operators/values_join.go @@ -160,7 +160,7 @@ func (vj *ValuesJoin) GetOrdering(ctx *plancontext.PlanningContext) []OrderBy { } func (vj *ValuesJoin) planOffsets(ctx *plancontext.PlanningContext) Operator { - exprs := ctx.ValuesJoinColumns[vj.ValuesDestination] + exprs := ctx.GetColumns(vj.ValuesDestination) for _, jc := range vj.JoinColumns { newExprs := vj.planOffsetsForLHSExprs(ctx, jc.LHS) exprs = append(exprs, newExprs...) @@ -172,7 +172,7 @@ func (vj *ValuesJoin) planOffsets(ctx *plancontext.PlanningContext) Operator { newExprs := vj.planOffsetsForLHSExprs(ctx, jc.LHS) exprs = append(exprs, newExprs...) } - ctx.ValuesJoinColumns[vj.ValuesDestination] = exprs + ctx.SetColumns(vj.ValuesDestination, exprs) return vj } diff --git a/go/vt/vtgate/planbuilder/plancontext/planning_context.go b/go/vt/vtgate/planbuilder/plancontext/planning_context.go index 1963bc9a4c0..c48fb9fa7b3 100644 --- a/go/vt/vtgate/planbuilder/plancontext/planning_context.go +++ b/go/vt/vtgate/planbuilder/plancontext/planning_context.go @@ -474,6 +474,15 @@ func (ctx *PlanningContext) ActiveCTE() *ContextCTE { return ctx.CurrentCTE[len(ctx.CurrentCTE)-1] } +func (ctx *PlanningContext) GetColumns(joinName string) []*sqlparser.AliasedExpr { + valuesName := ctx.ValueJoins[joinName] + return ctx.ValuesJoinColumns[valuesName] +} +func (ctx *PlanningContext) SetColumns(joinName string, cols []*sqlparser.AliasedExpr) { + valuesName := ctx.ValueJoins[joinName] + ctx.ValuesJoinColumns[valuesName] = cols +} + func (ctx *PlanningContext) UseMirror() *PlanningContext { if ctx.isMirrored { panic(vterrors.VT13001("cannot mirror already mirrored planning context")) diff --git a/go/vt/vtgate/planbuilder/testdata/onecase.json b/go/vt/vtgate/planbuilder/testdata/onecase.json index 9d653b2f6e9..279fd68988a 100644 --- a/go/vt/vtgate/planbuilder/testdata/onecase.json +++ b/go/vt/vtgate/planbuilder/testdata/onecase.json @@ -1,7 +1,7 @@ [ { "comment": "Add your test case here for debugging and run go test -run=One.", - "query": "", + "query": "select /*vt+ ALLOW_VALUES_JOIN */ user.foo, user_extra.user_id, user_metadata.name from user, user_extra, user_metadata where user.id = user_extra.toto and user_extra.age = user_metadata.age", "plan": { } } diff --git a/go/vt/vtgate/semantics/table_set.go b/go/vt/vtgate/semantics/table_set.go index acc83306869..65d714fc340 100644 --- a/go/vt/vtgate/semantics/table_set.go +++ b/go/vt/vtgate/semantics/table_set.go @@ -18,6 +18,7 @@ package semantics import ( "fmt" + "strings" "vitess.io/vitess/go/vt/vtgate/semantics/bitset" ) @@ -41,6 +42,22 @@ func (ts TableSet) Format(f fmt.State, verb rune) { fmt.Fprintf(f, "}") } +func (ts TableSet) DebugString() string { + var f strings.Builder + first := true + f.WriteString("TableSet{") + bitset.Bitset(ts).ForEach(func(tid int) { + if first { + f.WriteString(fmt.Sprintf("%d", tid)) + first = false + } else { + f.WriteString(fmt.Sprintf(",%d", tid)) + } + }) + f.WriteString("}") + return f.String() +} + // IsOverlapping returns true if at least one table exists in both sets func (ts TableSet) IsOverlapping(other TableSet) bool { return bitset.Bitset(ts).Overlaps(bitset.Bitset(other))