Skip to content

Commit 238a550

Browse files
Fix query planning for complex queries with impossible conditions.
Signed-off-by: Arthur Schreiber <[email protected]>
1 parent 3dd1516 commit 238a550

File tree

3 files changed

+102
-6
lines changed

3 files changed

+102
-6
lines changed

go/vt/vtgate/planbuilder/operators/subquery_builder.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ func createSubquery(
171171
sqc := &SubQueryBuilder{totalID: totalID, subqID: subqID, outerID: outerID}
172172

173173
predicates, joinCols := sqc.inspectStatement(ctx, subq.Select)
174-
correlated := !ctx.SemTable.RecursiveDeps(subq).IsEmpty()
174+
175+
subqDependencies := ctx.SemTable.RecursiveDeps(subq)
176+
correlated := subqDependencies.KeepOnly(outerID).NotEmpty()
175177

176178
opInner := translateQueryToOp(ctx, subq.Select)
177179

@@ -209,7 +211,9 @@ func createSubqueryFromPath(
209211
sqc := &SubQueryBuilder{totalID: totalID, subqID: subqID, outerID: outerID}
210212

211213
predicates, joinCols := sqc.inspectStatement(ctx, subq.Select)
212-
correlated := !ctx.SemTable.RecursiveDeps(subq).IsEmpty()
214+
215+
subqDependencies := ctx.SemTable.RecursiveDeps(subq)
216+
correlated := subqDependencies.KeepOnly(outerID).NotEmpty()
213217

214218
opInner := translateQueryToOp(ctx, subq.Select)
215219

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

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4411,7 +4411,7 @@
44114411
]
44124412
}
44134413
},
4414-
{
4414+
{
44154415
"comment": "Subquery with `IN` condition using columns with matching lookup vindexes, with inner scatter query",
44164416
"query": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.foo = 'bar') AND music.user_id IN (3, 4, 5)",
44174417
"plan": {
@@ -4438,6 +4438,85 @@
44384438
},
44394439
"skip_e2e": true
44404440
},
4441+
{
4442+
"comment": "Subquery with `IN` condition using columns with matching lookup vindexes, impossible conditions and limit clause",
4443+
"query": "SELECT music.id FROM music WHERE music.id IN (SELECT * FROM (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3) AND 1 = 0 AND music.foo = 'bar' LIMIT 0, 100) _inner)",
4444+
"plan": {
4445+
"Type": "Complex",
4446+
"QueryType": "SELECT",
4447+
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT * FROM (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3) AND 1 = 0 AND music.foo = 'bar' LIMIT 0, 100) _inner)",
4448+
"Instructions": {
4449+
"OperatorType": "UncorrelatedSubquery",
4450+
"Variant": "PulloutIn",
4451+
"PulloutVars": [
4452+
"__sq_has_values",
4453+
"__sq1"
4454+
],
4455+
"Inputs": [
4456+
{
4457+
"InputName": "SubQuery",
4458+
"OperatorType": "Limit",
4459+
"Count": "100",
4460+
"Offset": "0",
4461+
"Inputs": [
4462+
{
4463+
"OperatorType": "Route",
4464+
"Variant": "None",
4465+
"Keyspace": {
4466+
"Name": "user",
4467+
"Sharded": true
4468+
},
4469+
"FieldQuery": "select id from (select music.id from music where 1 != 1) as _inner where 1 != 1",
4470+
"Query": "select id from (select music.id from music where 0) as _inner limit 100"
4471+
}
4472+
]
4473+
},
4474+
{
4475+
"InputName": "Outer",
4476+
"OperatorType": "VindexLookup",
4477+
"Variant": "IN",
4478+
"Keyspace": {
4479+
"Name": "user",
4480+
"Sharded": true
4481+
},
4482+
"Values": [
4483+
"::__sq1"
4484+
],
4485+
"Vindex": "music_user_map",
4486+
"Inputs": [
4487+
{
4488+
"OperatorType": "Route",
4489+
"Variant": "IN",
4490+
"Keyspace": {
4491+
"Name": "user",
4492+
"Sharded": true
4493+
},
4494+
"FieldQuery": "select `name`, keyspace_id from name_user_vdx where 1 != 1",
4495+
"Query": "select `name`, keyspace_id from name_user_vdx where `name` in ::__vals",
4496+
"Values": [
4497+
"::name"
4498+
],
4499+
"Vindex": "user_index"
4500+
},
4501+
{
4502+
"OperatorType": "Route",
4503+
"Variant": "ByDestination",
4504+
"Keyspace": {
4505+
"Name": "user",
4506+
"Sharded": true
4507+
},
4508+
"FieldQuery": "select music.id from music where 1 != 1",
4509+
"Query": "select music.id from music where :__sq_has_values and music.id in ::__vals"
4510+
}
4511+
]
4512+
}
4513+
]
4514+
},
4515+
"TablesUsed": [
4516+
"user.music"
4517+
]
4518+
}
4519+
},
44414520
{
44424521
"comment": "Subquery with `IN` condition using columns with matching lookup vindexes",
44434522
"query": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3)) and music.user_id = 5",
@@ -6372,10 +6451,10 @@
63726451
},
63736452
"FieldQuery": "select r from (select rank() over (partition by col) as r from `user` where 1 != 1) as t where 1 != 1",
63746453
"Query": "select r from (select rank() over (partition by col) as r from `user` where id = 1) as t",
6375-
"Vindex": "user_index",
63766454
"Values": [
63776455
"1"
6378-
]
6456+
],
6457+
"Vindex": "user_index"
63796458
},
63806459
"TablesUsed": [
63816460
"user.user"

go/vt/vtgate/semantics/semantic_table.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,20 @@ func (st *SemTable) CopySemanticInfo(from, to sqlparser.SQLNode) {
544544
if !ok {
545545
return
546546
}
547-
st.CopyDependencies(f, t)
547+
548+
// Not all expressions are valid map keys
549+
if !ValidAsMapKey(t) || !ValidAsMapKey(f) {
550+
return
551+
}
552+
553+
if _, ok := t.(*sqlparser.ColName); ok {
554+
// If this is introducing a new column, we should copy all dependencies over
555+
// as we can't recalculate them later
556+
st.CopyDependencies(f, t)
557+
} else {
558+
// Otherwise, we only copy over the type information
559+
st.ExprTypes[t] = st.ExprTypes[f]
560+
}
548561
case *sqlparser.Union:
549562
t, ok := to.(*sqlparser.Union)
550563
if !ok {

0 commit comments

Comments
 (0)