vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/delete_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package engine
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"testing"
    23  
    24  	"vitess.io/vitess/go/mysql/collations"
    25  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/sqltypes"
    30  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    31  
    32  	querypb "vitess.io/vitess/go/vt/proto/query"
    33  )
    34  
    35  func TestDeleteUnsharded(t *testing.T) {
    36  	del := &Delete{
    37  		DML: &DML{
    38  			RoutingParameters: &RoutingParameters{
    39  				Opcode: Unsharded,
    40  				Keyspace: &vindexes.Keyspace{
    41  					Name:    "ks",
    42  					Sharded: false,
    43  				},
    44  			},
    45  			Query: "dummy_delete",
    46  		},
    47  	}
    48  
    49  	vc := newDMLTestVCursor("0")
    50  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    51  	require.NoError(t, err)
    52  	vc.ExpectLog(t, []string{
    53  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
    54  		`ExecuteMultiShard ks.0: dummy_delete {} true true`,
    55  	})
    56  
    57  	// Failure cases
    58  	vc = &loggingVCursor{shardErr: errors.New("shard_error")}
    59  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    60  	require.EqualError(t, err, "shard_error")
    61  
    62  	vc = &loggingVCursor{}
    63  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    64  	require.EqualError(t, err, "Keyspace 'ks' does not have exactly one shard: []")
    65  }
    66  
    67  func TestDeleteEqual(t *testing.T) {
    68  	vindex, _ := vindexes.NewHash("", nil)
    69  	del := &Delete{
    70  		DML: &DML{
    71  			RoutingParameters: &RoutingParameters{
    72  				Opcode: Equal,
    73  				Keyspace: &vindexes.Keyspace{
    74  					Name:    "ks",
    75  					Sharded: true,
    76  				},
    77  				Vindex: vindex,
    78  				Values: []evalengine.Expr{evalengine.NewLiteralInt(1)},
    79  			},
    80  			Query: "dummy_delete",
    81  		},
    82  	}
    83  
    84  	vc := newDMLTestVCursor("-20", "20-")
    85  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    86  	require.NoError(t, err)
    87  	vc.ExpectLog(t, []string{
    88  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
    89  		`ExecuteMultiShard ks.-20: dummy_delete {} true true`,
    90  	})
    91  
    92  	// Failure case
    93  	expr := evalengine.NewBindVar("aa", collations.TypedCollation{})
    94  	del.Values = []evalengine.Expr{expr}
    95  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    96  	require.EqualError(t, err, "query arguments missing for aa")
    97  }
    98  
    99  func TestDeleteEqualMultiCol(t *testing.T) {
   100  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
   101  	del := &Delete{
   102  		DML: &DML{
   103  			RoutingParameters: &RoutingParameters{
   104  				Opcode: Equal,
   105  				Keyspace: &vindexes.Keyspace{
   106  					Name:    "ks",
   107  					Sharded: true,
   108  				},
   109  				Vindex: vindex,
   110  				Values: []evalengine.Expr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)},
   111  			},
   112  			Query: "dummy_delete",
   113  		},
   114  	}
   115  
   116  	vc := newDMLTestVCursor("-20", "20-")
   117  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   118  	require.NoError(t, err)
   119  	vc.ExpectLog(t, []string{
   120  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
   121  		`ExecuteMultiShard ks.-20: dummy_delete {} true true`,
   122  	})
   123  
   124  	// Failure case
   125  	expr := evalengine.NewBindVar("aa", collations.TypedCollation{})
   126  	del.Values = []evalengine.Expr{expr}
   127  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   128  	require.EqualError(t, err, "query arguments missing for aa")
   129  }
   130  
   131  func TestDeleteEqualNoRoute(t *testing.T) {
   132  	vindex, _ := vindexes.NewLookupUnique("", map[string]string{
   133  		"table": "lkp",
   134  		"from":  "from",
   135  		"to":    "toc",
   136  	})
   137  	del := &Delete{
   138  		DML: &DML{
   139  			RoutingParameters: &RoutingParameters{
   140  				Opcode: Equal,
   141  				Keyspace: &vindexes.Keyspace{
   142  					Name:    "ks",
   143  					Sharded: true,
   144  				},
   145  				Vindex: vindex,
   146  				Values: []evalengine.Expr{evalengine.NewLiteralInt(1)},
   147  			},
   148  			Query: "dummy_delete",
   149  		},
   150  	}
   151  
   152  	vc := newDMLTestVCursor("0")
   153  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   154  	require.NoError(t, err)
   155  	vc.ExpectLog(t, []string{
   156  		// This lookup query will return no rows. So, the DML will not be sent anywhere.
   157  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   158  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   159  	})
   160  }
   161  
   162  func TestDeleteEqualNoScatter(t *testing.T) {
   163  	t.Skip("planner does not produces this plan anymore")
   164  	vindex, _ := vindexes.NewLookupUnique("", map[string]string{
   165  		"table":      "lkp",
   166  		"from":       "from",
   167  		"to":         "toc",
   168  		"write_only": "true",
   169  	})
   170  	del := &Delete{
   171  		DML: &DML{
   172  			RoutingParameters: &RoutingParameters{
   173  				Opcode: Equal,
   174  				Keyspace: &vindexes.Keyspace{
   175  					Name:    "ks",
   176  					Sharded: true,
   177  				},
   178  				Vindex: vindex,
   179  				Values: []evalengine.Expr{evalengine.NewLiteralInt(1)},
   180  			},
   181  			Query: "dummy_delete",
   182  		},
   183  	}
   184  
   185  	vc := newDMLTestVCursor("0")
   186  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   187  	require.EqualError(t, err, "cannot map vindex to unique keyspace id: DestinationKeyRange(-)")
   188  }
   189  
   190  func TestDeleteOwnedVindex(t *testing.T) {
   191  	ks := buildTestVSchema().Keyspaces["sharded"]
   192  	del := &Delete{
   193  		DML: &DML{
   194  			RoutingParameters: &RoutingParameters{
   195  				Opcode:   Equal,
   196  				Keyspace: ks.Keyspace,
   197  				Vindex:   ks.Vindexes["hash"],
   198  				Values:   []evalengine.Expr{evalengine.NewLiteralInt(1)},
   199  			},
   200  			Query: "dummy_delete",
   201  			Table: []*vindexes.Table{
   202  				ks.Tables["t1"],
   203  			},
   204  			OwnedVindexQuery: "dummy_subquery",
   205  			KsidVindex:       ks.Vindexes["hash"],
   206  			KsidLength:       1,
   207  		},
   208  	}
   209  
   210  	results := []*sqltypes.Result{sqltypes.MakeTestResult(
   211  		sqltypes.MakeTestFields(
   212  			"id|c1|c2|c3",
   213  			"int64|int64|int64|int64",
   214  		),
   215  		"1|4|5|6",
   216  	)}
   217  
   218  	vc := newDMLTestVCursor("-20", "20-")
   219  	vc.results = results
   220  
   221  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   222  	require.NoError(t, err)
   223  	vc.ExpectLog(t, []string{
   224  		`ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   225  		// ResolveDestinations is hard-coded to return -20.
   226  		// It gets used to perform the subquery to fetch the changing column values.
   227  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   228  		// Those values are returned as 4,5 for twocol and 6 for onecol.
   229  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   230  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   231  		// Finally, the actual delete, which is also sent to -20, same route as the subquery.
   232  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   233  	})
   234  
   235  	// No rows changing
   236  	vc = newDMLTestVCursor("-20", "20-")
   237  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   238  	require.NoError(t, err)
   239  	vc.ExpectLog(t, []string{
   240  		`ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   241  		// ResolveDestinations is hard-coded to return -20.
   242  		// It gets used to perform the subquery to fetch the changing column values.
   243  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   244  		// Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete.
   245  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   246  	})
   247  
   248  	// Delete can affect multiple rows
   249  	results = []*sqltypes.Result{sqltypes.MakeTestResult(
   250  		sqltypes.MakeTestFields(
   251  			"id|c1|c2|c3",
   252  			"int64|int64|int64|int64",
   253  		),
   254  		"1|4|5|6",
   255  		"1|7|8|9",
   256  	)}
   257  	vc = newDMLTestVCursor("-20", "20-")
   258  	vc.results = results
   259  
   260  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   261  	require.NoError(t, err)
   262  	vc.ExpectLog(t, []string{
   263  		`ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   264  		// ResolveDestinations is hard-coded to return -20.
   265  		// It gets used to perform the subquery to fetch the changing column values.
   266  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   267  		// Delete 4,5 and 7,8 from lkp2.
   268  		// Delete 6 and 8 from lkp1.
   269  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   270  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   271  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"7" from2: type:INT64 value:"8" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   272  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"9" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   273  		// Send the DML.
   274  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   275  	})
   276  }
   277  
   278  func TestDeleteOwnedVindexMultiCol(t *testing.T) {
   279  	ks := buildTestVSchema().Keyspaces["sharded"]
   280  	del := &Delete{
   281  		DML: &DML{
   282  			RoutingParameters: &RoutingParameters{
   283  				Opcode:   Equal,
   284  				Keyspace: ks.Keyspace,
   285  				Vindex:   ks.Vindexes["rg_vdx"],
   286  				Values:   []evalengine.Expr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)},
   287  			},
   288  			Query: "dummy_delete",
   289  			Table: []*vindexes.Table{
   290  				ks.Tables["rg_tbl"],
   291  			},
   292  			OwnedVindexQuery: "dummy_subquery",
   293  			KsidVindex:       ks.Vindexes["rg_vdx"],
   294  			KsidLength:       2,
   295  		},
   296  	}
   297  
   298  	results := []*sqltypes.Result{sqltypes.MakeTestResult(
   299  		sqltypes.MakeTestFields(
   300  			"cola|colb|colc",
   301  			"int64|int64|int64",
   302  		),
   303  		"1|2|4",
   304  	)}
   305  
   306  	vc := newDMLTestVCursor("-20", "20-")
   307  	vc.results = results
   308  
   309  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   310  	require.NoError(t, err)
   311  	vc.ExpectLog(t, []string{
   312  		`ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
   313  		// ResolveDestinations is hard-coded to return -20.
   314  		// It gets used to perform the subquery to fetch the changing column values.
   315  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   316  		// 4 returned for lkp_rg.
   317  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`,
   318  		// Finally, the actual delete, which is also sent to -20, same route as the subquery.
   319  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   320  	})
   321  
   322  	// No rows changing
   323  	vc.Rewind()
   324  	vc.results = nil
   325  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   326  	require.NoError(t, err)
   327  	vc.ExpectLog(t, []string{
   328  		`ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
   329  		// ResolveDestinations is hard-coded to return -20.
   330  		// It gets used to perform the subquery to fetch the changing column values.
   331  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   332  		// Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete.
   333  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   334  	})
   335  
   336  	// Delete can affect multiple rows
   337  	results = []*sqltypes.Result{sqltypes.MakeTestResult(
   338  		sqltypes.MakeTestFields(
   339  			"cola|colb|colc",
   340  			"int64|int64|int64",
   341  		),
   342  		"1|2|4",
   343  		"1|2|6",
   344  	)}
   345  	vc.Rewind()
   346  	vc.results = results
   347  
   348  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   349  	require.NoError(t, err)
   350  	vc.ExpectLog(t, []string{
   351  		`ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
   352  		// ResolveDestinations is hard-coded to return -20.
   353  		// It gets used to perform the subquery to fetch the changing column values.
   354  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   355  		// Delete 4 and 6 from lkp_rg.
   356  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`,
   357  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`,
   358  		// Send the DML.
   359  		`ExecuteMultiShard sharded.-20: dummy_delete {} true true`,
   360  	})
   361  }
   362  
   363  func TestDeleteSharded(t *testing.T) {
   364  	ks := buildTestVSchema().Keyspaces["sharded"]
   365  	del := &Delete{
   366  		DML: &DML{
   367  			RoutingParameters: &RoutingParameters{
   368  				Opcode:   Scatter,
   369  				Keyspace: ks.Keyspace,
   370  			},
   371  			Query: "dummy_delete",
   372  			Table: []*vindexes.Table{
   373  				ks.Tables["t2"],
   374  			},
   375  		},
   376  	}
   377  
   378  	vc := newDMLTestVCursor("-20", "20-")
   379  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   380  	require.NoError(t, err)
   381  	vc.ExpectLog(t, []string{
   382  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
   383  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   384  	})
   385  
   386  	// Failure case
   387  	vc = &loggingVCursor{shardErr: errors.New("shard_error")}
   388  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   389  	require.EqualError(t, err, "shard_error")
   390  }
   391  
   392  func TestDeleteShardedStreaming(t *testing.T) {
   393  	ks := buildTestVSchema().Keyspaces["sharded"]
   394  	del := &Delete{
   395  		DML: &DML{
   396  			RoutingParameters: &RoutingParameters{
   397  				Opcode:   Scatter,
   398  				Keyspace: ks.Keyspace,
   399  			},
   400  			Query: "dummy_delete",
   401  			Table: []*vindexes.Table{
   402  				ks.Tables["t2"],
   403  			},
   404  		},
   405  	}
   406  
   407  	vc := newDMLTestVCursor("-20", "20-")
   408  	err := del.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
   409  		return nil
   410  	})
   411  	require.NoError(t, err)
   412  	vc.ExpectLog(t, []string{
   413  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
   414  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   415  	})
   416  }
   417  
   418  func TestDeleteScatterOwnedVindex(t *testing.T) {
   419  	ks := buildTestVSchema().Keyspaces["sharded"]
   420  	del := &Delete{
   421  		DML: &DML{
   422  			RoutingParameters: &RoutingParameters{
   423  				Opcode:   Scatter,
   424  				Keyspace: ks.Keyspace,
   425  			},
   426  			Query: "dummy_delete",
   427  			Table: []*vindexes.Table{
   428  				ks.Tables["t1"],
   429  			},
   430  			OwnedVindexQuery: "dummy_subquery",
   431  			KsidVindex:       ks.Vindexes["hash"],
   432  			KsidLength:       1,
   433  		},
   434  	}
   435  
   436  	results := []*sqltypes.Result{sqltypes.MakeTestResult(
   437  		sqltypes.MakeTestFields(
   438  			"id|c1|c2|c3",
   439  			"int64|int64|int64|int64",
   440  		),
   441  		"1|4|5|6",
   442  	)}
   443  
   444  	vc := newDMLTestVCursor("-20", "20-")
   445  	vc.results = results
   446  
   447  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   448  	require.NoError(t, err)
   449  	vc.ExpectLog(t, []string{
   450  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
   451  		// ResolveDestinations is hard-coded to return -20.
   452  		// It gets used to perform the subquery to fetch the changing column values.
   453  		`ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`,
   454  		// Those values are returned as 4,5 for twocol and 6 for onecol.
   455  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   456  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   457  		// Finally, the actual delete, which is also sent to -20, same route as the subquery.
   458  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   459  	})
   460  
   461  	// No rows changing
   462  	vc = newDMLTestVCursor("-20", "20-")
   463  
   464  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   465  	require.NoError(t, err)
   466  	vc.ExpectLog(t, []string{
   467  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
   468  		// ResolveDestinations is hard-coded to return -20.
   469  		// It gets used to perform the subquery to fetch the changing column values.
   470  		`ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`,
   471  		// Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete.
   472  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   473  	})
   474  
   475  	// Delete can affect multiple rows
   476  	results = []*sqltypes.Result{sqltypes.MakeTestResult(
   477  		sqltypes.MakeTestFields(
   478  			"id|c1|c2|c3",
   479  			"int64|int64|int64|int64",
   480  		),
   481  		"1|4|5|6",
   482  		"1|7|8|9",
   483  	)}
   484  	vc = newDMLTestVCursor("-20", "20-")
   485  	vc.results = results
   486  
   487  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   488  	require.NoError(t, err)
   489  	vc.ExpectLog(t, []string{
   490  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
   491  		// ResolveDestinations is hard-coded to return -20.
   492  		// It gets used to perform the subquery to fetch the changing column values.
   493  		`ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`,
   494  		// Delete 4,5 and 7,8 from lkp2.
   495  		// Delete 6 and 8 from lkp1.
   496  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   497  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   498  		`Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"7" from2: type:INT64 value:"8" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   499  		`Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"9" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`,
   500  		// Send the DML.
   501  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   502  	})
   503  }
   504  
   505  func TestDeleteInChangedVindexMultiCol(t *testing.T) {
   506  	ks := buildTestVSchema().Keyspaces["sharded"]
   507  	del := &Delete{
   508  		DML: &DML{
   509  			RoutingParameters: &RoutingParameters{
   510  				Opcode:   IN,
   511  				Keyspace: ks.Keyspace,
   512  				Vindex:   ks.Vindexes["rg_vdx"],
   513  				Values: []evalengine.Expr{
   514  					evalengine.TupleExpr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)},
   515  					evalengine.NewLiteralInt(3),
   516  				},
   517  			},
   518  			Query: "dummy_update",
   519  			Table: []*vindexes.Table{
   520  				ks.Tables["rg_tbl"],
   521  			},
   522  			OwnedVindexQuery: "dummy_subquery",
   523  			KsidVindex:       ks.Vindexes["rg_vdx"],
   524  			KsidLength:       2,
   525  		},
   526  	}
   527  
   528  	results := []*sqltypes.Result{sqltypes.MakeTestResult(
   529  		sqltypes.MakeTestFields(
   530  			"cola|colb|colc",
   531  			"int64|int64|int64",
   532  		),
   533  		"1|3|4",
   534  		"2|3|5",
   535  		"1|3|6",
   536  		"2|3|7",
   537  	)}
   538  	vc := newDMLTestVCursor("-20", "20-")
   539  	vc.results = results
   540  
   541  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   542  	require.NoError(t, err)
   543  	vc.ExpectLog(t, []string{
   544  		`ResolveDestinationsMultiCol sharded [[INT64(1) INT64(3)] [INT64(2) INT64(3)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(024eb190c9a2fa169c)`,
   545  		// ResolveDestinations is hard-coded to return -20.
   546  		// It gets used to perform the subquery to fetch the changing column values.
   547  		`ExecuteMultiShard sharded.-20: dummy_subquery {} false false`,
   548  		// Those values are returned as 4,5,6 and 7 for colc
   549  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01N\xb1\x90ɢ\xfa\x16\x9c" true`,
   550  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"5" toc: type:VARBINARY value:"\x02N\xb1\x90ɢ\xfa\x16\x9c" true`,
   551  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x01N\xb1\x90ɢ\xfa\x16\x9c" true`,
   552  		`Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"7" toc: type:VARBINARY value:"\x02N\xb1\x90ɢ\xfa\x16\x9c" true`,
   553  		// Finally, the actual delete, which is also sent to -20, same route as the subquery.
   554  		`ExecuteMultiShard sharded.-20: dummy_update {} true true`,
   555  	})
   556  }
   557  
   558  func TestDeleteEqualSubshard(t *testing.T) {
   559  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
   560  	del := &Delete{
   561  		DML: &DML{
   562  			RoutingParameters: &RoutingParameters{
   563  				Opcode: SubShard,
   564  				Keyspace: &vindexes.Keyspace{
   565  					Name:    "ks",
   566  					Sharded: true,
   567  				},
   568  				Vindex: vindex,
   569  				Values: []evalengine.Expr{evalengine.NewLiteralInt(1)},
   570  			},
   571  			Query: "dummy_delete",
   572  		},
   573  	}
   574  
   575  	vc := newDMLTestVCursor("-20", "20-")
   576  	vc.shardForKsid = []string{"-20", "20-"}
   577  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   578  	require.NoError(t, err)
   579  	vc.ExpectLog(t, []string{
   580  		`ResolveDestinationsMultiCol ks [[INT64(1)]] Destinations:DestinationKeyRange(01-02)`,
   581  		`ExecuteMultiShard ks.-20: dummy_delete {} ks.20-: dummy_delete {} true false`,
   582  	})
   583  
   584  	vc.Rewind()
   585  	// as it is single shard so autocommit should be allowed.
   586  	vc.shardForKsid = []string{"-20"}
   587  	_, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   588  	require.NoError(t, err)
   589  	vc.ExpectLog(t, []string{
   590  		`ResolveDestinationsMultiCol ks [[INT64(1)]] Destinations:DestinationKeyRange(01-02)`,
   591  		`ExecuteMultiShard ks.-20: dummy_delete {} true true`,
   592  	})
   593  }
   594  
   595  func TestDeleteMultiEqual(t *testing.T) {
   596  	ks := buildTestVSchema().Keyspaces["sharded"]
   597  	del := &Delete{
   598  		DML: &DML{
   599  			RoutingParameters: &RoutingParameters{
   600  				Opcode:   MultiEqual,
   601  				Keyspace: ks.Keyspace,
   602  				Vindex:   ks.Vindexes["hash"],
   603  				Values: []evalengine.Expr{evalengine.NewTupleExpr(
   604  					evalengine.NewLiteralInt(1),
   605  					evalengine.NewLiteralInt(5),
   606  				)},
   607  			},
   608  			Query: "dummy_delete",
   609  		},
   610  	}
   611  
   612  	vc := newDMLTestVCursor("-20", "20-")
   613  	vc.shardForKsid = []string{"-20", "20-"}
   614  	_, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   615  	require.NoError(t, err)
   616  	vc.ExpectLog(t, []string{
   617  		`ResolveDestinations sharded [type:INT64 value:"1" type:INT64 value:"5"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(70bb023c810ca87a)`,
   618  		`ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`,
   619  	})
   620  }