Repository: vitessio/vitess
Pull request #7730 (2021-03-23 14:06:49)

make sure to handle subqueries on top of subqueries
## Description

Planning subqueries on top of subqueries was not working as expected. We broke planning of this with the 9.0 release. This is to fix this regression.

## Related Issue(s)
#7682 

## Checklist
- [x] Should this PR be backported? `Yes, to the release-9.0 branch`
- [x] Tests were added or are not required `Added`
- [x] Documentation was added or is not required

## Impacted Areas in Vitess
Components that this PR will affect:

- [x]  Query Serving



Patch:
diff --git a/go/vt/vtgate/planbuilder/filtering.go b/go/vt/vtgate/planbuilder/filtering.go
index 336b719cf9..4621cf169a 100644
--- a/go/vt/vtgate/planbuilder/filtering.go
+++ b/go/vt/vtgate/planbuilder/filtering.go
@@ -64,7 +64,12 @@ func planFilter(pb *primitiveBuilder, input logicalPlan, filter sqlparser.Expr,
 		node.UpdatePlan(pb, filter)
 		return node, nil
 	case *pulloutSubquery:
-		return planFilter(pb, node.underlying, filter, whereType, origin)
+		plan, err := planFilter(pb, node.underlying, filter, whereType, origin)
+		if err != nil {
+			return nil, err
+		}
+		node.underlying = plan
+		return node, nil
 	case *vindexFunc:
 		return filterVindexFunc(node, filter)
 	case *subquery:


Test patch:
diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go
index 3dc1f55aa5..fba70cfbc7 100644
--- a/go/test/endtoend/vtgate/misc_test.go
+++ b/go/test/endtoend/vtgate/misc_test.go
@@ -581,6 +581,20 @@ func TestOrderBy(t *testing.T) {
 	assertMatches(t, conn, "select id1, id2 from t4 order by id1 desc", `[[INT64(8) VARCHAR("F")] [INT64(7) VARCHAR("e")] [INT64(6) VARCHAR("d")] [INT64(5) VARCHAR("test")] [INT64(4) VARCHAR("c")] [INT64(3) VARCHAR("b")] [INT64(2) VARCHAR("Abc")] [INT64(1) VARCHAR("a")]]`)
 }
 
+func TestSubQueryOnTopOfSubQuery(t *testing.T) {
+	defer cluster.PanicHandler(t)
+	ctx := context.Background()
+	conn, err := mysql.Connect(ctx, &vtParams)
+	require.NoError(t, err)
+	defer conn.Close()
+	defer exec(t, conn, `delete from t1`)
+
+	exec(t, conn, `insert into t1(id1, id2) values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)`)
+	exec(t, conn, `insert into t2(id3, id4) values (1, 3), (2, 4)`)
+
+	assertMatches(t, conn, "select id1 from t1 where id1 not in (select id3 from t2) and id2 in (select id4 from t2)", `[[INT64(3)] [INT64(4)]]`)
+}
+
 func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) {
 	t.Helper()
 	qr := exec(t, conn, query)
diff --git a/go/vt/vtexplain/testdata/multi-output/selectsharded-output.txt b/go/vt/vtexplain/testdata/multi-output/selectsharded-output.txt
index 0ee841517c..6fe933c375 100644
--- a/go/vt/vtexplain/testdata/multi-output/selectsharded-output.txt
+++ b/go/vt/vtexplain/testdata/multi-output/selectsharded-output.txt
@@ -166,3 +166,9 @@ select id, 'abc' as test from user where id = 1 union all select id, 'def' as te
 1 ks_sharded/-40: select id, 'abc' as test from `user` where id = 1 union all select id, 'def' as test from `user` where id = 1 union all select id, 'ghi' as test from `user` where id = 1 limit 10001 /* union all */
 
 ----------------------------------------------------------------------
+select id from user where not id in (select col from music where music.user_id = 42) and id in (select col from music where music.user_id = 411)
+
+1 ks_sharded/40-80: select col from music where music.user_id = 42 limit 10001
+2 ks_sharded/40-80: select col from music where music.user_id = 411 limit 10001
+
+----------------------------------------------------------------------
diff --git a/go/vt/vtexplain/testdata/selectsharded-queries.sql b/go/vt/vtexplain/testdata/selectsharded-queries.sql
index e2fdfc3171..a32e1a6cd2 100644
--- a/go/vt/vtexplain/testdata/selectsharded-queries.sql
+++ b/go/vt/vtexplain/testdata/selectsharded-queries.sql
@@ -32,3 +32,5 @@ select id, case when name = 'alice' then 'ALICE' when name = 'bob' then 'BOB' el
 select id, case when substr(name, 1, 5) = 'alice' then 'ALICE' when name = 'bob' then 'BOB' else 'OTHER' end as name from user where id = 1 /* select case */;
 
 select id, 'abc' as test from user where id = 1 union all select id, 'def' as test from user where id = 1 union all select id, 'ghi' as test from user where id = 1 /* union all */;
+
+select id from user where not id in (select col from music where music.user_id = 42) and id in (select col from music where music.user_id = 411);
diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
index 125be6f87d..a04993f162 100644
--- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
@@ -1869,19 +1869,40 @@ Gen4 plan same as above
         "Vindex": "user_index"
       },
       {
-        "OperatorType": "Route",
-        "Variant": "SelectIN",
-        "Keyspace": {
-          "Name": "user",
-          "Sharded": true
-        },
-        "FieldQuery": "select id from `user` where 1 != 1",
-        "Query": "select id from `user` where :__sq_has_values1 = 1 and id in ::__vals and not (:__sq_has_values2 = 1 and id in ::__sq2)",
-        "Table": "`user`",
-        "Values": [
-          "::__sq1"
-        ],
-        "Vindex": "user_index"
+        "OperatorType": "Subquery",
+        "Variant": "PulloutIn",
+        "Inputs": [
+          {
+            "OperatorType": "Route",
+            "Variant": "SelectEqualUnique",
+            "Keyspace": {
+              "Name": "user",
+              "Sharded": true
+            },
+            "FieldQuery": "select user_extra.col from user_extra where 1 != 1",
+            "Query": "select user_extra.col from user_extra where user_extra.user_id = 411",
+            "Table": "user_extra",
+            "Values": [
+              411
+            ],
+            "Vindex": "user_index"
+          },
+          {
+            "OperatorType": "Route",
+            "Variant": "SelectIN",
+            "Keyspace": {
+              "Name": "user",
+              "Sharded": true
+            },
+            "FieldQuery": "select id from `user` where 1 != 1",
+            "Query": "select id from `user` where :__sq_has_values1 = 1 and id in ::__vals and not (:__sq_has_values2 = 1 and id in ::__sq2)",
+            "Table": "`user`",
+            "Values": [
+              "::__sq1"
+            ],
+            "Vindex": "user_index"
+          }
+        ]
       }
     ]
   }