Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
systay committed Feb 26, 2025
1 parent b05df12 commit 21d3199
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 11 deletions.
33 changes: 33 additions & 0 deletions go/vt/sqlparser/ast_rewrite.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions go/vt/sqlparser/ast_visit.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 15 additions & 8 deletions go/vt/vtgate/planbuilder/operators/apply_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"maps"
"slices"
"strings"
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/predicates"

"vitess.io/vitess/go/slice"
"vitess.io/vitess/go/vt/sqlparser"
Expand Down Expand Up @@ -69,10 +70,11 @@ type (
// so they can be used for the result of this expression that is using data from both sides.
// All fields will be used for these
applyJoinColumn struct {
Original sqlparser.Expr // this is the original expression being passed through
LHSExprs []BindVarExpr // These are the expressions we are pushing to the left hand side which we'll receive as bind variables
RHSExpr sqlparser.Expr // This the expression that we'll evaluate on the right hand side. This is nil, if the right hand side has nothing.
GroupBy bool // if this is true, we need to push this down to our inputs with addToGroupBy set to true
PredicateID predicates.ID
Original sqlparser.Expr // this is the original expression being passed through
LHSExprs []BindVarExpr // These are the expressions we are pushing to the left hand side which we'll receive as bind variables
RHSExpr sqlparser.Expr // This the expression that we'll evaluate on the right hand side. This is nil, if the right hand side has nothing.
GroupBy bool // if this is true, we need to push this down to our inputs with addToGroupBy set to true
}

// BindVarExpr is an expression needed from one side of a join/subquery, and the argument name for it.
Expand Down Expand Up @@ -144,12 +146,17 @@ func (aj *ApplyJoin) AddJoinPredicate(ctx *plancontext.PlanningContext, expr sql
return
}
rhs := aj.RHS
predicates := sqlparser.SplitAndExpression(nil, expr)
for _, pred := range predicates {
col := breakExpressionInLHSandRHS(ctx, pred, TableID(aj.LHS))
preds := sqlparser.SplitAndExpression(nil, expr)
for _, pred := range preds {
lhsID := TableID(aj.LHS)
col := breakExpressionInLHSandRHS(ctx, pred, lhsID)
newPred := ctx.PredTracker.NewPredicate(pred, lhsID, "")
newPred.ApplyJoinPredicate = col.RHSExpr
col.PredicateID = newPred.ID
aj.JoinPredicates.add(col)

ctx.AddJoinPredicates(pred, col.RHSExpr)
rhs = rhs.AddPredicate(ctx, col.RHSExpr)
rhs = rhs.AddPredicate(ctx, newPred)
}
aj.RHS = rhs
}
Expand Down
52 changes: 52 additions & 0 deletions go/vt/vtgate/planbuilder/operators/predicates/predicate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2025 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 predicates

import (
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vtgate/semantics"
)

// Predicate represents a condition relating two parts of the query,
// typically used when expressions span multiple tables. We track it in
// different shapes so we can rewrite or push it differently during plan generation.
type Predicate struct {
ID ID
LHS, RHS semantics.TableSet
tracker *Tracker
}

var _ sqlparser.Expr = (*Predicate)(nil)
var _ sqlparser.Visitable = (*Predicate)(nil)

func (j *Predicate) Inputs() []sqlparser.SQLNode {
return []sqlparser.SQLNode{j.current()}
}

func (j *Predicate) current() sqlparser.Expr {
return j.tracker.Expressions[j.ID]
}

func (j *Predicate) IsExpr() {}

func (j *Predicate) Format(buf *sqlparser.TrackedBuffer) {
j.current().Format(buf)
}

func (j *Predicate) FormatFast(buf *sqlparser.TrackedBuffer) {
j.current().FormatFast(buf)
}
68 changes: 68 additions & 0 deletions go/vt/vtgate/planbuilder/operators/predicates/tracker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
Copyright 2025 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 predicates

import (
"sync"
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vtgate/semantics"
)

type (
// Tracker manages a global mapping of expression IDs to their "Shape".
// This allows the same logical expression to take different forms (shapes)
// depending on pushdown or join strategies. We lock around 'lastID' to ensure
// unique IDs in concurrent planning contexts.
Tracker struct {
mu sync.Mutex
lastID ID
Expressions map[ID]sqlparser.Expr
}

// ID is a unique key that references the shape of a single expression.
// We use it so multiple references to an expression can share the same shape entry.
ID int
)

func NewTracker() *Tracker {
return &Tracker{
Expressions: make(map[ID]sqlparser.Expr),
}
}

func (t *Tracker) NewPredicate(org sqlparser.Expr, lhs, rhs semantics.TableSet) *Predicate {
t.Expressions[t.NextID()] = org
return &Predicate{
ID: t.NextID(),
Original: org,
LHS: lhs,
RHS: rhs,
tracker: t,
}
}

func (t *Tracker) NextID() ID {
t.mu.Lock()
defer t.mu.Unlock()
id := t.lastID
t.lastID++
return id
}

func (t *Tracker) GetPushDownExpression(pred *Predicate) sqlparser.Expr {
return t.Expressions[pred.ID]
}
3 changes: 3 additions & 0 deletions go/vt/vtgate/planbuilder/operators/query_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ func mergeOffsetExpressions(e1, e2 sqlparser.Expr) (expr sqlparser.Expr, failed
}

// mergeLimitExpressions merges two LIMIT expressions with an OFFSET expression.

// select tbl1.foo = tbl2.bar from tbl1, tbl2 where tbl1.foo = tbl2.bar

// l1: First LIMIT expression.
// l2: Second LIMIT expression.
// off2: Second OFFSET expression.
Expand Down
7 changes: 7 additions & 0 deletions go/vt/vtgate/planbuilder/operators/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package operators

import (
"fmt"
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/predicates"

"vitess.io/vitess/go/slice"
"vitess.io/vitess/go/vt/key"
Expand Down Expand Up @@ -128,6 +129,12 @@ func UpdateRoutingLogic(ctx *plancontext.PlanningContext, expr sqlparser.Expr, r
}

// For some expressions, even if we can't evaluate them, we know that they will always return false or null
pred, ok := expr.(*predicates.Predicate)
if !ok {
return exit()
}

expr = ctx.PredTracker.GetPushDownExpression(pred)
cmp, ok := expr.(*sqlparser.ComparisonExpr)
if !ok {
return exit()
Expand Down
5 changes: 5 additions & 0 deletions go/vt/vtgate/planbuilder/plancontext/planning_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package plancontext

import (
"io"
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/predicates"

"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
Expand Down Expand Up @@ -79,6 +80,8 @@ type PlanningContext struct {

emptyEnv *evalengine.ExpressionEnv
constantCfg *evalengine.Config

PredTracker *predicates.Tracker
}

// CreatePlanningContext initializes a new PlanningContext with the given parameters.
Expand Down Expand Up @@ -112,6 +115,7 @@ func CreatePlanningContext(stmt sqlparser.Statement,
PlannerVersion: version,
ReservedArguments: map[sqlparser.Expr]string{},
Statement: stmt,
PredTracker: predicates.NewTracker(),
}, nil
}

Expand Down Expand Up @@ -456,6 +460,7 @@ func (ctx *PlanningContext) UseMirror() *PlanningContext {
OuterTables: ctx.OuterTables,
CurrentCTE: ctx.CurrentCTE,
emptyEnv: ctx.emptyEnv,
PredTracker: ctx.PredTracker,
isMirrored: true,
}
return ctx.mirror
Expand Down
2 changes: 2 additions & 0 deletions go/vt/vtgate/planbuilder/plancontext/planning_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"
"testing"
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/predicates"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -181,6 +182,7 @@ func createPlanContext(st *semantics.SemTable) *PlanningContext {
skipPredicates: map[sqlparser.Expr]any{},
ReservedArguments: map[sqlparser.Expr]string{},
VSchema: &vschema{},
PredTracker: predicates.NewTracker(),
}
}

Expand Down
21 changes: 18 additions & 3 deletions go/vt/vtgate/planbuilder/testdata/onecase.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
[
{
"comment": "Add your test case here for debugging and run go test -run=One.",
"query": "",
"query": "select id from user where someColumn = null",
"plan": {
}
}
"QueryType": "SELECT",
"Original": "select id from user where someColumn = null",
"Instructions": {
"OperatorType": "Route",
"Variant": "None",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select id from `user` where 1 != 1",
"Query": "select id from `user` where someColumn = null",
"Table": "`user`"
},
"TablesUsed": [
"user.user"
]
} }
]

0 comments on commit 21d3199

Please sign in to comment.