Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Harshit Gangal <harshit@planetscale.com>
  • Loading branch information
harshit-gangal committed Sep 5, 2024
1 parent c16fa1e commit 31a48fb
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 34 deletions.
37 changes: 37 additions & 0 deletions go/vt/vtgate/planbuilder/operators/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,43 @@ func breakExpressionInLHSandRHS(
return
}

// original query:
// select a.v1 + b.v2 + c.v3 from a, b, c where a.v1 = b.v2 and b.v2 = c.v3

// select a.v1 from a
// select a.v1 + b.v2 a c1, b.v2 from (values ::a) a(v1), b where a.v1 = b.v2
// select d.c1 + c.v3 from (values ::d) d(c1, v2), c where d.v2 = c.v3

func valuesJoinExpressionSplit(ctx *plancontext.PlanningContext, expr sqlparser.Expr, lhs semantics.TableSet, tableName string) (lhsExprs []*sqlparser.AliasedExpr, rhsExpr sqlparser.Expr) {
var replace sqlparser.Expr
rhsExpr = sqlparser.CopyOnRewrite(expr, func(node, parent sqlparser.SQLNode) bool {
nodeExpr, ok := node.(sqlparser.Expr)
if !ok {
return true
}

deps := ctx.SemTable.RecursiveDeps(nodeExpr)
if !deps.IsSolvedBy(lhs) || deps.IsEmpty() {
return true
}

alias := ""
if col, ok := nodeExpr.(*sqlparser.ColName); !ok {

Check failure on line 84 in go/vt/vtgate/planbuilder/operators/expressions.go

View workflow job for this annotation

GitHub Actions / Static Code Checks Etc

ineffectual assignment to col (ineffassign)
alias = ctx.GetUniqueColumnName()
col = sqlparser.NewColNameWithQualifier(alias, sqlparser.NewTableName(tableName))
replace = col
}
lhsExprs = append(lhsExprs, sqlparser.NewAliasedExpr(nodeExpr, alias))
return false
}, func(cursor *sqlparser.CopyOnWriteCursor) {
if replace != nil {
cursor.Replace(replace)
replace = nil
}
}, ctx.SemTable.CopySemanticInfo).(sqlparser.Expr)
return
}

// nothingNeedsFetching will return true if all the nodes in the expression are constant
func nothingNeedsFetching(ctx *plancontext.PlanningContext, expr sqlparser.Expr) (constant bool) {
constant = true
Expand Down
28 changes: 14 additions & 14 deletions go/vt/vtgate/planbuilder/operators/projection_pushing.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ func tryPushProjection(
return p, NoRewrite
}
return pushProjectionThroughHashJoin(ctx, p, src)
case *ValuesJoin:
return pushProjectionUnderValueJoin(ctx, p, src)
// case *ValuesJoin:
// return pushProjectionUnderValueJoin(ctx, p, src)
case *Vindex:
if !p.canPush(ctx) {
return p, NoRewrite
Expand All @@ -110,18 +110,18 @@ func tryPushProjection(
}
}

func pushProjectionUnderValueJoin(ctx *plancontext.PlanningContext, p *Projection, join *ValuesJoin) (Operator, *ApplyResult) {
// We need to push all the columns needed from the LHS
exprs := p.GetColumns(ctx)
for _, expr := range exprs {
col := breakExpressionInLHSandRHS(ctx, expr.Expr, TableID(join.LHS))
join.addLHSExprs(col.LHSExprs)
}

// We can now push the projection under the values join
p.Source, join.RHS = join.RHS, p
return join, Rewrote("push projection under valuesJoin")
}
// func pushProjectionUnderValueJoin(ctx *plancontext.PlanningContext, p *Projection, join *ValuesJoin) (Operator, *ApplyResult) {
// // We need to push all the columns needed from the LHS
// exprs := p.GetColumns(ctx)
// for _, expr := range exprs {
// lhsExprs, rhsExpr := valuesJoinExpressionSplit(ctx, expr.Expr, TableID(join.LHS), join.TableName)
// join.LHSExprs = append(join.LHSExprs, lhsExprs...)
// }
//
// // We can now push the projection under the values join
// p.Source, join.RHS = join.RHS, p
// return join, Rewrote("push projection under valuesJoin")
// }

// pushProjectionThroughHashJoin optimizes projection operations within a hash join
func pushProjectionThroughHashJoin(ctx *plancontext.PlanningContext, p *Projection, hj *HashJoin) (Operator, *ApplyResult) {
Expand Down
3 changes: 3 additions & 0 deletions go/vt/vtgate/planbuilder/operators/route_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ func requiresSwitchingSides(ctx *plancontext.PlanningContext, op Operator) (requ
return
}

// select 1 from user u join user_extra ue on ue.id = u.id
// ue.id = ::u_id

// Will create a join valid for the current mysql version
func createJoin(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinType sqlparser.JoinType, joinPredicates []sqlparser.Expr) (join JoinOp) {
sigOk := ctx.SemTable.QuerySignature.EmptySet()
Expand Down
33 changes: 14 additions & 19 deletions go/vt/vtgate/planbuilder/operators/values_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type ValuesJoin struct {
binaryOperator

JoinType sqlparser.JoinType
LHSExprs sqlparser.Exprs
LHSExprs []*sqlparser.AliasedExpr
ListArg string // the bindvar name for the list of values
TableName string // the name of the derived table that will be created

Expand Down Expand Up @@ -83,8 +83,9 @@ func (vj *ValuesJoin) AddPredicate(ctx *plancontext.PlanningContext, expr sqlpar
}

func (vj *ValuesJoin) AddColumn(ctx *plancontext.PlanningContext, reuseExisting bool, addToGroupBy bool, expr *sqlparser.AliasedExpr) int {
col := breakExpressionInLHSandRHS(ctx, expr.Expr, TableID(vj.LHS))
vj.addLHSExprs(col.LHSExprs)
lhsExprs, rhsExpr := valuesJoinExpressionSplit(ctx, expr.Expr, TableID(vj.LHS), vj.TableName)
vj.LHSExprs = append(vj.LHSExprs, lhsExprs...)
expr.Expr = rhsExpr
return vj.RHS.AddColumn(ctx, reuseExisting, addToGroupBy, expr)
}

Expand Down Expand Up @@ -129,39 +130,33 @@ func (vj *ValuesJoin) AddJoinPredicate(ctx *plancontext.PlanningContext, expr sq
}
predicates := sqlparser.SplitAndExpression(nil, expr)
for _, pred := range predicates {
col := breakExpressionInLHSandRHS(ctx, pred, TableID(vj.LHS))

if col.IsPureLeft() && vj.JoinType.IsInner() {
lhsID := TableID(vj.LHS)
deps := ctx.SemTable.RecursiveDeps(pred)
if deps.IsSolvedBy(lhsID) {
// If the predicate doesn't reference the RHS, we can add it to the LHS
// This is only valid for inner joins
vj.LHS = vj.LHS.AddPredicate(ctx, pred)
} else {
vj.addLHSExprs(col.LHSExprs)
vj.RHS = vj.RHS.AddPredicate(ctx, pred)
continue
}
lhsExprs, rhsExpr := valuesJoinExpressionSplit(ctx, pred, lhsID, vj.TableName)
vj.LHSExprs = append(vj.LHSExprs, lhsExprs...)
vj.RHS = vj.RHS.AddPredicate(ctx, rhsExpr)
}
}

func (vj *ValuesJoin) planOffsets(ctx *plancontext.PlanningContext) Operator {
vj.Vars = make(map[string]int)
for _, expr := range vj.LHSExprs {
argName := ctx.GetReservedArgumentFor(expr)
argName := ctx.GetReservedArgumentFor(expr.Expr)
_, ok := vj.Vars[argName]
if ok {
// already have this expression
continue
}
ae := aeWrap(expr)
vj.Columns = append(vj.Columns, ae.ColumnName())
offset := vj.LHS.AddColumn(ctx, true, false, ae)
vj.Columns = append(vj.Columns, expr.ColumnName())
offset := vj.LHS.AddColumn(ctx, true, false, expr)
vj.Vars[argName] = offset
}
ctx.Columns[vj.ListArg] = vj.Columns
return vj
}

func (vj *ValuesJoin) addLHSExprs(exprs []BindVarExpr) {
for _, exp := range exprs {
vj.LHSExprs = append(vj.LHSExprs, exp.Expr)
}
}
11 changes: 11 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"
"strconv"

"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
Expand All @@ -28,11 +29,15 @@ import (
"vitess.io/vitess/go/vt/vtgate/semantics"
)

const columnPrefix = "_vtcol"

type PlanningContext struct {
ReservedVars *sqlparser.ReservedVars
SemTable *semantics.SemTable
VSchema VSchema

reservedColCount int

// joinPredicates maps each original join predicate (key) to a slice of
// variations of the RHS predicates (value). This map is used to handle
// different scenarios in join planning, where the RHS predicates are
Expand Down Expand Up @@ -119,6 +124,12 @@ func CreatePlanningContext(stmt sqlparser.Statement,
}, nil
}

// GetUniqueColumnName generates a unique column name for the current planning context.
func (ctx *PlanningContext) GetUniqueColumnName() string {
ctx.reservedColCount++
return columnPrefix + strconv.Itoa(ctx.reservedColCount)
}

// GetReservedArgumentFor retrieves a reserved argument name for a given expression.
// If the expression already has a reserved argument, it returns that name;
// otherwise, it reserves a new name based on the expression type.
Expand Down
2 changes: 1 addition & 1 deletion go/vt/vtgate/planbuilder/testdata/onecase.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"comment": "Add your test case here for debugging and run go test -run=One.",
"query": "",
"query": "select u.foo+u.bar+ue.baz from user u join user_extra ue on u.foo = ue.user_id",
"plan": {
}
}
Expand Down

0 comments on commit 31a48fb

Please sign in to comment.