Repository: vitessio/vitess
Pull request #6554 (2020-08-12 13:31:43)

support vindex update or delete when destination is provided by client in dml query
Fixes: https://github.com/vitessio/vitess/issues/6541


Patch:
diff --git a/go/vt/vtgate/planbuilder/dml.go b/go/vt/vtgate/planbuilder/dml.go
index 67da3070e3..7fcd57983e 100644
--- a/go/vt/vtgate/planbuilder/dml.go
+++ b/go/vt/vtgate/planbuilder/dml.go
@@ -146,19 +146,20 @@ func buildDMLPlan(vschema ContextVSchema, dmlType string, stmt sqlparser.Stateme
 		return nil, nil, "", vterrors.New(vtrpcpb.Code_INTERNAL, "internal error: table.vindexTable is mysteriously nil")
 	}
 
+	routingType, ksidVindex, ksidCol, vindex, values, err := getDMLRouting(where, eupd.Table)
+	if err != nil {
+		return nil, nil, "", err
+	}
+
 	if ro.eroute.TargetDestination != nil {
 		if ro.eroute.TargetTabletType != topodatapb.TabletType_MASTER {
 			return nil, nil, "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported: %s statement with a replica target", dmlType)
 		}
 		eupd.Opcode = engine.ByDestination
 		eupd.TargetDestination = ro.eroute.TargetDestination
-		return eupd, nil, "", nil
+		return eupd, ksidVindex, ksidCol, nil
 	}
 
-	routingType, ksidVindex, ksidCol, vindex, values, err := getDMLRouting(where, eupd.Table)
-	if err != nil {
-		return nil, nil, "", err
-	}
 	eupd.Opcode = routingType
 	if routingType == engine.Scatter {
 		if limit != nil {


Test patch:
diff --git a/go/test/endtoend/vtgate/lookup_test.go b/go/test/endtoend/vtgate/lookup_test.go
index a5b485399c..ffc019073b 100644
--- a/go/test/endtoend/vtgate/lookup_test.go
+++ b/go/test/endtoend/vtgate/lookup_test.go
@@ -203,7 +203,7 @@ func TestDMLScatter(t *testing.T) {
 	3 4
 	4 5
 	*/
-	exec(t, conn, "update t3 set id5 = 42 where id5 = 1")
+	exec(t, conn, "update `ks[-]`.t3 set id5 = 42 where id5 = 1")
 	qr = exec(t, conn, "select id5, id6, id7 from t3 order by id5")
 	if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(2) INT64(2) INT64(3)] [INT64(3) INT64(4) INT64(3)] [INT64(4) INT64(5) INT64(4)] [INT64(42) INT64(2) INT64(3)]]"; got != want {
 		t.Errorf("select:\n%v want\n%v", got, want)
@@ -246,7 +246,7 @@ func TestDMLScatter(t *testing.T) {
 	require.Empty(t, qr.Rows)
 
 	// delete all the rows.
-	exec(t, conn, "delete from t3")
+	exec(t, conn, "delete from `ks[-]`.t3")
 	qr = exec(t, conn, "select * from t3")
 	require.Empty(t, qr.Rows)
 	qr = exec(t, conn, "select * from t3_id7_idx")
diff --git a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
index 0f43e3b861..1edb0c69d6 100644
--- a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
@@ -2101,3 +2101,67 @@
     "Vindex": "kid_index"
   }
 }
+
+# delete with shard targeting
+"delete from `user[-]`.user"
+{
+  "QueryType": "DELETE",
+  "Original": "delete from `user[-]`.user",
+  "Instructions": {
+    "OperatorType": "Delete",
+    "Variant": "ByDestination",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "TargetTabletType": "MASTER",
+    "KsidVindex": "user_index",
+    "MultiShardAutocommit": false,
+    "OwnedVindexQuery": "select Id, Name, Costly from user for update",
+    "Query": "delete from user",
+    "Table": "user"
+  }
+}
+
+# update with shard targeting
+"update `user[-]`.user set name = 'myname'"
+{
+  "QueryType": "UPDATE",
+  "Original": "update `user[-]`.user set name = 'myname'",
+  "Instructions": {
+    "OperatorType": "Update",
+    "Variant": "ByDestination",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "TargetTabletType": "MASTER",
+    "ChangedVindexValues": [
+      "name_user_map"
+    ],
+    "KsidVindex": "user_index",
+    "MultiShardAutocommit": false,
+    "OwnedVindexQuery": "select Id, Name, Costly from user for update",
+    "Query": "update user set name = 'myname'",
+    "Table": "user"
+  }
+}
+
+# update with shard targeting without vindex
+"update `user[-]`.user_extra set val = 1"
+{
+  "QueryType": "UPDATE",
+  "Original": "update `user[-]`.user_extra set val = 1",
+  "Instructions": {
+    "OperatorType": "Update",
+    "Variant": "ByDestination",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "TargetTabletType": "MASTER",
+    "MultiShardAutocommit": false,
+    "Query": "update user_extra set val = 1",
+    "Table": "user_extra"
+  }
+}