Skip to content

Commit 47d9053

Browse files
Delegate Column Availability Checks to MySQL for Single-Route Queries (#17077)
Signed-off-by: Harshit Gangal <harshit@planetscale.com> Signed-off-by: Andres Taylor <andres@planetscale.com> Co-authored-by: Andres Taylor <andres@planetscale.com>
1 parent ed60cc0 commit 47d9053

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

go/vt/vtgate/planbuilder/operators/operator.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import (
4444
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops"
4545
"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/rewrite"
4646
"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
47+
"vitess.io/vitess/go/vt/vtgate/semantics"
4748
)
4849

4950
type (
@@ -81,10 +82,8 @@ func PlanQuery(ctx *plancontext.PlanningContext, stmt sqlparser.Statement) (ops.
8182
return nil, err
8283
}
8384

84-
_, isRoute := op.(*Route)
85-
if !isRoute && ctx.SemTable.NotSingleRouteErr != nil {
86-
// If we got here, we don't have a single shard plan
87-
return nil, ctx.SemTable.NotSingleRouteErr
85+
if err := checkSingleRouteError(ctx, op); err != nil {
86+
return nil, err
8887
}
8988

9089
return op, err
@@ -161,3 +160,27 @@ func transformColumnsToSelectExprs(ctx *plancontext.PlanningContext, op ops.Oper
161160
})
162161
return selExprs, nil
163162
}
163+
164+
// checkSingleRouteError checks if the query has a NotSingleRouteErr and more than one route, and returns an error if it does
165+
func checkSingleRouteError(ctx *plancontext.PlanningContext, op ops.Operator) error {
166+
if ctx.SemTable.NotSingleRouteErr == nil {
167+
return nil
168+
}
169+
routes := 0
170+
visitF := func(op ops.Operator, _ semantics.TableSet, _ bool) (ops.Operator, *rewrite.ApplyResult, error) {
171+
switch op.(type) {
172+
case *Route:
173+
routes++
174+
}
175+
return op, rewrite.SameTree, nil
176+
}
177+
178+
// we'll walk the tree and count the number of routes
179+
_, _ = rewrite.TopDown(op, TableID, visitF, stopAtRoute)
180+
181+
if routes <= 1 {
182+
return nil
183+
}
184+
185+
return ctx.SemTable.NotSingleRouteErr
186+
}

go/vt/vtgate/planbuilder/testdata/select_cases.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@
6565
]
6666
}
6767
},
68+
{
69+
"comment": "join on sharding column with limit - should be a simple scatter query and limit on top with non resolved columns",
70+
"query": "select * from user u join user_metadata um on u.id = um.user_id where foo=41 limit 20",
71+
"plan": {
72+
"QueryType": "SELECT",
73+
"Original": "select * from user u join user_metadata um on u.id = um.user_id where foo=41 limit 20",
74+
"Instructions": {
75+
"OperatorType": "Limit",
76+
"Count": "INT64(20)",
77+
"Inputs": [
78+
{
79+
"OperatorType": "Route",
80+
"Variant": "Scatter",
81+
"Keyspace": {
82+
"Name": "user",
83+
"Sharded": true
84+
},
85+
"FieldQuery": "select * from `user` as u, user_metadata as um where 1 != 1",
86+
"Query": "select * from `user` as u, user_metadata as um where foo = 41 and u.id = um.user_id limit :__upper_limit",
87+
"Table": "`user`, user_metadata"
88+
}
89+
]
90+
},
91+
"TablesUsed": [
92+
"user.user",
93+
"user.user_metadata"
94+
]
95+
}
96+
},
6897
{
6998
"comment": "select with timeout directive sets QueryTimeout in the route",
7099
"query": "select /*vt+ QUERY_TIMEOUT_MS=1000 */ * from user",

0 commit comments

Comments
 (0)