Repository: vitessio/vitess
Pull request #7776 (2021-04-01 09:47:20)

[9.0] make sure to handle subqueries on top of subqueries
Backport of #7730 


Patch:
diff --git a/go/vt/vtgate/planbuilder/filtering.go b/go/vt/vtgate/planbuilder/filtering.go
index 4e22a3cdbc..6b442a2f16 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 415d67a284..09a075556a 100644
--- a/go/test/endtoend/vtgate/misc_test.go
+++ b/go/test/endtoend/vtgate/misc_test.go
@@ -496,6 +496,20 @@ func TestCreateView(t *testing.T) {
 	assertMatches(t, conn, "select * from v1", `[[INT64(1) INT64(1)] [INT64(2) INT64(2)] [INT64(3) INT64(3)] [INT64(4) INT64(4)] [INT64(5) INT64(5)]]`)
 }
 
+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 ccad112665..f17fa13e4c 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 038e498bc6..a2ba4862a3 100644
--- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
@@ -1799,19 +1799,40 @@
         "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"
+          }
+        ]
       }
     ]
   }