Skip to content

Commit a0ca6d8

Browse files
committed
v3: fix UNION merge logic
UNION mergeability was previously using the same logic as subquery mergeability. It turns out that it doesn't always work because subqueries can have outer query dependencies whereas unions don't have such relationship. So, the logic has now been separated.
1 parent 315cd85 commit a0ca6d8

File tree

4 files changed

+54
-11
lines changed

4 files changed

+54
-11
lines changed

data/test/vtgate/select_cases.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,23 @@
565565
}
566566
}
567567

568+
# union with the same target shard
569+
"select * from music where user_id = 1 union select * from user where id = 1"
570+
{
571+
"Original": "select * from music where user_id = 1 union select * from user where id = 1",
572+
"Instructions": {
573+
"Opcode": "SelectEqualUnique",
574+
"Keyspace": {
575+
"Name": "user",
576+
"Sharded": true
577+
},
578+
"Query": "select * from music where user_id = 1 union select * from user where id = 1",
579+
"FieldQuery": "select * from music where 1 != 1 union select * from user where 1 != 1",
580+
"Vindex": "user_index",
581+
"Values": 1
582+
}
583+
}
584+
568585
"select * from (select col1, col2 from unsharded where id = 1 union select col1, col2 from unsharded where id = 3) a"
569586
{
570587
"Original": "select * from (select col1, col2 from unsharded where id = 1 union select col1, col2 from unsharded where id = 3) a",

data/test/vtgate/unsupported_cases.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Unions
22
"select * from user union select * from user_extra"
3-
"unsupported: scatter subquery"
3+
"unsupported: UNION on multi-shard queries"
44

55
# SET
66
"set a=1"
@@ -29,11 +29,11 @@
2929

3030
# union operations in subqueries (FROM)
3131
"select * from (select * from user union all select * from user_extra) as t"
32-
"unsupported: scatter subquery"
32+
"unsupported: UNION on multi-shard queries"
3333

3434
# union operations in subqueries (expressions)
3535
"select * from user where id in (select * from user union select * from user_extra)"
36-
"unsupported: scatter subquery"
36+
"unsupported: UNION on multi-shard queries"
3737

3838
# subquery with join primitive (FROM)
3939
"select * from (select user.id from user join user_extra) as t"
@@ -265,23 +265,27 @@
265265

266266
# multi-shard union
267267
"(select id from user union select id from music) union select 1 from dual"
268-
"unsupported: scatter subquery"
268+
"unsupported: UNION on multi-shard queries"
269269

270270
# multi-shard union
271271
"select 1 from music union (select id from user union all select name from unsharded)"
272-
"unsupported: subquery keyspace different from outer query"
272+
"unsupported: UNION on different keyspaces"
273273

274274
# multi-shard union
275275
"select 1 from music union (select id from user union select name from unsharded)"
276-
"unsupported: subquery keyspace different from outer query"
276+
"unsupported: UNION on different keyspaces"
277277

278278
# multi-shard union
279279
"select id from user union all select id from music"
280-
"unsupported: scatter subquery"
280+
"unsupported: UNION on multi-shard queries"
281+
282+
# union with different target shards
283+
"select 1 from music where id = 1 union select 1 from music where id = 2"
284+
"unsupported: UNION queries with different target shards"
281285

282286
# Union all
283287
"select col1, col2 from user union all select col1, col2 from user_extra"
284-
"unsupported: scatter subquery"
288+
"unsupported: UNION on multi-shard queries"
285289

286290
"(select user.id, user.name from user join user_extra where user_extra.extra = 'asdf') union select 'b','c' from user"
287291
"unsupported construct: SELECT of UNION is non-trivial"

go/vt/vtgate/planbuilder/expr.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func findRoute(expr sqlparser.Expr, bldr builder) (rb *route, err error) {
9393
return nil, err
9494
}
9595
for _, subroute := range subroutes {
96-
err = routesCanMerge(highestRoute, subroute)
96+
err = subqueryCanMerge(highestRoute, subroute)
9797
if err != nil {
9898
return nil, err
9999
}
@@ -104,10 +104,10 @@ func findRoute(expr sqlparser.Expr, bldr builder) (rb *route, err error) {
104104
return highestRoute, nil
105105
}
106106

107-
// routesCanMerge returns nil if the inner subquery
107+
// subqueryCanMerge returns nil if the inner subquery
108108
// can be merged with the specified outer route. If it
109109
// cannot, then it returns an appropriate error.
110-
func routesCanMerge(outer, inner *route) error {
110+
func subqueryCanMerge(outer, inner *route) error {
111111
if outer.ERoute.Keyspace.Name != inner.ERoute.Keyspace.Name {
112112
return errors.New("unsupported: subquery keyspace different from outer query")
113113
}

go/vt/vtgate/planbuilder/union.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,25 @@ func unionRouteMerge(union *sqlparser.Union, left, right builder, vschema VSchem
9595
rroute.Redirect = rtb
9696
return rtb, nil
9797
}
98+
99+
// routesCanMerge returns nil if the left and right route
100+
// can be merged. Otherwise, it returns an appropriate error.
101+
func routesCanMerge(left, right *route) error {
102+
if left.ERoute.Opcode == engine.SelectNext || right.ERoute.Opcode == engine.SelectNext {
103+
return errors.New("unsupported: UNION on sequence tables")
104+
}
105+
if left.ERoute.Keyspace.Name != right.ERoute.Keyspace.Name {
106+
return errors.New("unsupported: UNION on different keyspaces")
107+
}
108+
if left.ERoute.Opcode == engine.SelectUnsharded {
109+
// right will also be unsharded. So, we're good.
110+
return nil
111+
}
112+
if left.ERoute.Opcode != engine.SelectEqualUnique || right.ERoute.Opcode != engine.SelectEqualUnique {
113+
return errors.New("unsupported: UNION on multi-shard queries")
114+
}
115+
if !valEqual(left.ERoute.Values, right.ERoute.Values) {
116+
return errors.New("unsupported: UNION queries with different target shards")
117+
}
118+
return nil
119+
}

0 commit comments

Comments
 (0)