Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go/vt/vtgate/planbuilder/physical/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,8 @@ func (r *Route) planCompositeInOpRecursive(
return foundVindex
}

// Reset all vindex predicates on this route and re-build their options from
// the list of seen routing predicates.
func (r *Route) resetRoutingSelections(ctx *plancontext.PlanningContext) error {
switch r.RouteOpCode {
case engine.DBA, engine.Next, engine.Reference, engine.Unsharded:
Expand Down
1 change: 1 addition & 0 deletions go/vt/vtgate/planbuilder/physical/route_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ func createRouteOperatorForJoin(aRoute, bRoute *Route, joinPredicates []sqlparse
Keyspace: aRoute.Keyspace,
VindexPreds: append(aRoute.VindexPreds, bRoute.VindexPreds...),
SysTableTableSchema: append(aRoute.SysTableTableSchema, bRoute.SysTableTableSchema...),
SeenPredicates: append(aRoute.SeenPredicates, bRoute.SeenPredicates...),
SysTableTableName: sysTableName,
Source: &ApplyJoin{
LHS: aRoute.Source,
Expand Down
16 changes: 16 additions & 0 deletions go/vt/vtgate/planbuilder/physical/subquery_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ func mergeSubQueryOp(ctx *plancontext.PlanningContext, outer *Route, inner *Rout
outer.SysTableTableName[k] = v
}

// When merging an inner query with its outer query, we can remove the
// inner query from the list of predicates that can influence routing of
// the outer query.
//
// Note that not all inner queries necessarily are part of the routing
// predicates list, so this might be a no-op.
for i, predicate := range outer.SeenPredicates {
if sqlparser.EqualsExpr(predicate, subq.ExtractedSubquery) {
outer.SeenPredicates = append(outer.SeenPredicates[:i], outer.SeenPredicates[i+1:]...)

// The `ExtractedSubquery` of an inner query is unique (due to the uniqueness of bind variable names)
// so we can stop after the first match.
break
}
}

err = outer.resetRoutingSelections(ctx)
if err != nil {
return nil, err
Expand Down
45 changes: 45 additions & 0 deletions go/vt/vtgate/planbuilder/testdata/select_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4114,6 +4114,51 @@ Gen4 plan same as above
"unsupported: cross-shard correlated subquery"
Gen4 error: exists sub-queries are only supported with AND clause

# correlated subquery that is dependent on one side of a join, fully mergeable
"SELECT music.id FROM music INNER JOIN user ON music.user_id = user.id WHERE music.user_id = 5 AND music.id = (SELECT MAX(m2.id) FROM music m2 WHERE m2.user_id = user.id)"
{
"QueryType": "SELECT",
"Original": "SELECT music.id FROM music INNER JOIN user ON music.user_id = user.id WHERE music.user_id = 5 AND music.id = (SELECT MAX(m2.id) FROM music m2 WHERE m2.user_id = user.id)",
"Instructions": {
"OperatorType": "Route",
"Variant": "EqualUnique",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select music.id from music join `user` on music.user_id = `user`.id where 1 != 1",
"Query": "select music.id from music join `user` on music.user_id = `user`.id where music.user_id = 5 and music.id = (select max(m2.id) from music as m2 where m2.user_id = `user`.id)",
"Table": "music, `user`",
"Values": [
"INT64(5)"
],
"Vindex": "user_index"
}
}
{
"QueryType": "SELECT",
"Original": "SELECT music.id FROM music INNER JOIN user ON music.user_id = user.id WHERE music.user_id = 5 AND music.id = (SELECT MAX(m2.id) FROM music m2 WHERE m2.user_id = user.id)",
"Instructions": {
"OperatorType": "Route",
"Variant": "EqualUnique",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select music.id from music, `user` where 1 != 1",
"Query": "select music.id from music, `user` where music.user_id = 5 and music.id = (select max(m2.id) from music as m2 where m2.user_id = `user`.id) and music.user_id = `user`.id",
"Table": "`user`, music",
"Values": [
"INT64(5)"
],
"Vindex": "user_index"
},
"TablesUsed": [
"user.music",
"user.user"
]
}

# union as a derived table
"select found from (select id as found from user union all (select id from unsharded)) as t"
{
Expand Down